verquest 0.3.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ccc6bfd2d16a987d2ed8ae6c04a9fbfd72a0ed58f00699221193ef76e764cd0
4
- data.tar.gz: '0026964f349c5d17f41b18cd7f32431519c46f1530fe92a535488abcd202a86e'
3
+ metadata.gz: b9349b2773c4a03024805d78257b1e763ffb87b87f27726620e343395c683aa0
4
+ data.tar.gz: ec2b70a4a10c3314ca27283776138f85b53b245d88869de39e450ca2eb2064de
5
5
  SHA512:
6
- metadata.gz: dba0dc768c80d2f51cfb74a9c93483218c8d3f28fffffe01b41d250e78f0d2e504ba64af6ea2dd723de22640170b2151f860424bcdc5ad05b29d24fa694a5081
7
- data.tar.gz: 662c43fb095decd144c50afece842467ff96705bbe4a51f27a347a2fdf6041a0bc98895274f280a1441ca88f445a1820d519fc280f9304bc26826f44ea9fcb23
6
+ metadata.gz: 0d0042f959285f4253c7802166ab64d53b7013d765bfe954fd68a8ab46bb59f162512a285aca11c77e86a8e6b5ce36445f47e4e9530fcaa0010e8c6cadcefdf2
7
+ data.tar.gz: 06bbfceb1c989e1e3eabb20e495790ac35934e1cb4687e71960315c3e64d3a30b42b345c03d19d32be921b75550a6fef002d8ba44018ded8f7c9a3af73d920f0
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2025-07-01
4
+
5
+ ### Fixed
6
+ - Handling `with_options` defaults like required and nullable.
7
+
8
+ ### New Features
9
+ - Add `default_additional_properties` option to configuration.
10
+ - Add support for nullable properties (`nullable: true`) based on the latest JSON Schema specification, which is also used in OpenAPI 3.1.
11
+ - Add support for `dependentRequired` (see https://json-schema.org/understanding-json-schema/reference/conditionals#dependentRequired).
12
+
13
+ ## [0.4.0] - 2025-06-28
14
+
15
+ ### Breaking Changes
16
+ - **BREAKING:** Renaming validation method from `validate_schema` to `valid_schema?` to better reflect its purpose.
17
+ - **BREAKING:** The `validate_schema` now returns an array of errors instead of a boolean value, allowing for more detailed error reporting.
18
+
19
+ ### New Features
20
+ - Add support for custom field types.
21
+
22
+ ### Fixed
23
+ - Loading the gem in another project with `zeitwerk` now works correctly.
24
+ - Fix schema validation after `json_schemer` refactoring.
25
+
3
26
  ## [0.3.0] - 2025-06-25
4
27
 
5
28
  ### Breaking Changes
data/README.md CHANGED
@@ -19,7 +19,7 @@ Verquest is a Ruby gem that offers an elegant solution for versioning API reques
19
19
  Add this line to your application's Gemfile:
20
20
 
21
21
  ```ruby
22
- gem "verquest", "~> 0.2"
22
+ gem "verquest", "~> 0.5"
23
23
  ```
24
24
 
25
25
  And then execute:
@@ -62,7 +62,7 @@ class UserCreateRequest < Verquest::Base
62
62
  field :email, format: "email", description: "The email address of the user"
63
63
  end
64
64
 
65
- field :birth_date, type: :string, format: "date", description: "The birth date of the user"
65
+ field :birth_date, type: :string, nullable: true, format: "date", description: "The birth date of the user"
66
66
 
67
67
  reference :address, from: AddressCreateRequest, required: true
68
68
 
@@ -135,7 +135,7 @@ Output:
135
135
  "first_name" => {"type" => "string", "description" => "The first name of the user", "maxLength" => 50},
136
136
  "last_name" => {"type" => "string", "description" => "The last name of the user", "maxLength" => 50},
137
137
  "email" => {"type" => "string", "format" => "email", "description" => "The email address of the user"},
138
- "birth_date" => {"type" => "string", "format" => "date", "description" => "The birth date of the user"},
138
+ "birth_date" => {"type" => ["string", "null"], "format" => "date", "description" => "The birth date of the user"},
139
139
  "address" => {"$ref" => "#/components/schemas/AddressCreateRequest"},
140
140
  "permissions" => {
141
141
  "type" => "array",
@@ -174,7 +174,8 @@ Output:
174
174
  }
175
175
  }
176
176
  },
177
- "additionalProperties" => false}
177
+ "additionalProperties" => false
178
+ }
178
179
  ```
179
180
 
180
181
  ### JSON schema for validation
@@ -249,7 +250,8 @@ Output:
249
250
  You can also validate it to ensure it meets the JSON Schema standards:
250
251
 
251
252
  ```ruby
252
- UserCreateRequest.validate_schema(version: "2025-06") # => true/false
253
+ UserCreateRequest.valid_schema?(version: "2025-06") # => true/false
254
+ UserCreateRequest.validate_schema(version: "2025-06") # => Array of errors or empty array if valid
253
255
  ```
254
256
 
255
257
  ## Core Features
@@ -274,6 +276,156 @@ The JSON schema can be used for both validation of incoming parameters and for g
274
276
  - `schema_options`: Allows you to set additional options for the JSON Schema, such as `additional_properties` for request or per version. All fields (except `reference`) can be defined with options like `required`, `format`, `min_lenght`, `max_length`, etc. all in snake case.
275
277
  - `with_options`: Allows you to define multiple fields with the same options, reducing repetition.
276
278
 
279
+ ### Required properties
280
+
281
+ You can define required properties in your request schema by setting the `required` option to `true`, or provide a list of dependent required properties. This feature is based on the latest [JSON Schema specification](https://json-schema.org/understanding-json-schema/reference/conditionals#dependentRequired), which is also used in OpenAPI 3.1.
282
+
283
+ ```ruby
284
+ class DependentRequiredRequest < Verquest::Base
285
+ description "This is a simple request with nullable properties for testing purposes."
286
+
287
+ version "2025-06" do
288
+ field :name, type: :string, required: true
289
+ field :credit_card, type: :number, required: %i[billing_address]
290
+ field :billing_address, type: :string
291
+ end
292
+ end
293
+ ```
294
+
295
+ Will produce this validation schema:
296
+
297
+ ```ruby
298
+ {
299
+ "type" => "object",
300
+ "description" => "This is a simple request with nullable properties for testing purposes.",
301
+ "required" => ["name"],
302
+ "dependentRequired" => {"credit_card" => ["billing_address"]},
303
+ "properties" => {
304
+ "name" => {"type" => "string"},
305
+ "credit_card" => {"type" => "number"},
306
+ "billing_address" => {"type" => "string"}
307
+ },
308
+ "additionalProperties" => false
309
+ }
310
+ ```
311
+
312
+ #### Nullable properties
313
+
314
+ You can define nullable properties in your request schema by setting the `nullable` option to `true`. This feature is based on the latest JSON Schema specification, which is also used in OpenAPI 3.1.
315
+
316
+ ```ruby
317
+ class NullableRequest < Verquest::Base
318
+ description "This is a simple request with nullable properties for testing purposes."
319
+
320
+ version "2025-06" do
321
+ with_options nullable: true do
322
+ array :array, type: :string
323
+ collection :collection_with_item, item: ReferencedRequest
324
+ collection :collection_with_object do
325
+ field :field, type: :string, nullable: false
326
+ end
327
+
328
+ field :field, type: :string
329
+
330
+ object :object do
331
+ field :field, type: :string, nullable: false
332
+ end
333
+
334
+ reference :referenced_object, from: ReferencedRequest
335
+ reference :referenced_field, from: ReferencedRequest, property: :simple_field
336
+ end
337
+ end
338
+ end
339
+ ```
340
+
341
+ Will produce this validation schema:
342
+
343
+ ```ruby
344
+ {
345
+ "type" => "object",
346
+ "description" => "This is a simple request with nullable properties for testing purposes.",
347
+ "required" => [],
348
+ "properties" => {
349
+ "array" => {"type" => %w[array null], "items" => {"type" => "string"}},
350
+ "collection_with_item" => {"type" => %w[array null], "items" => {"type" => "object", "description" => "This is an another example for testing purposes.", "required" => %w[simple_field nested], "properties" => {"simple_field" => {"type" => "string", "description" => "The simple field"}, "nested" => {"type" => "object", "required" => %w[nested_field_1 nested_field_2], "properties" => {"nested_field_1" => {"type" => "string", "description" => "This is a nested field"}, "nested_field_2" => {"type" => "string", "description" => "This is another nested field"}}, "additionalProperties" => false}}, "additionalProperties" => false}},
351
+ "collection_with_object" => {"type" => %w[array null], "items" => {"type" => "object", "required" => [], "properties" => {"field" => {"type" => "string"}}, "additionalProperties" => false}},
352
+ "field" => {"type" => %w[string null]},
353
+ "object" => {
354
+ "type" => %w[object null],
355
+ "required" => [],
356
+ "properties" => {
357
+ "field" => {"type" => "string"}
358
+ },
359
+ "additionalProperties" => false
360
+ },
361
+ "referenced_object" => {
362
+ "type" => %w[object null],
363
+ "description" => "This is an another example for testing purposes.",
364
+ "required" => %w[simple_field nested],
365
+ "properties" => {"simple_field" => {"type" => "string", "description" => "The simple field"}, "nested" => {"type" => "object", "required" => %w[nested_field_1 nested_field_2], "properties" => {"nested_field_1" => {"type" => "string", "description" => "This is a nested field"}, "nested_field_2" => {"type" => "string", "description" => "This is another nested field"}}, "additionalProperties" => false}},
366
+ "additionalProperties" => false
367
+ },
368
+ "referenced_field" => {"type" => %w[string null], "description" => "The simple field"}
369
+ },
370
+ "additionalProperties" => false
371
+ }
372
+ ```
373
+
374
+ #### Custom Field Types
375
+
376
+ You can define custom field types that can be used in `field` and `array` in the configuration.
377
+
378
+ ```ruby
379
+ Verquest.configure do |config|
380
+ config.custom_field_types = {
381
+ email: {
382
+ type: "string",
383
+ schema_options: {format: "email"}
384
+ },
385
+ uuid: {
386
+ type: "string",
387
+ schema_options: {format: "uuid"}
388
+ }
389
+ }
390
+ end
391
+ ```
392
+
393
+ Then you can use it in your request:
394
+ ```ruby
395
+ class EmailRequest < Verquest::Base
396
+ description "User Create Request"
397
+ schema_options additional_properties: false
398
+
399
+ version "2025-06" do
400
+ field :email, type: :email
401
+ array :uuids, type: :uuid
402
+ end
403
+ end
404
+ ```
405
+
406
+ `EmailRequest.to_schema(version: "2025-06")` will then generate the following JSON Schema:
407
+ ```ruby
408
+ {
409
+ "type" => "object",
410
+ "description" => "User Create Request",
411
+ "required" => ["email"],
412
+ "properties" => {
413
+ "email" => {
414
+ "type" => "string",
415
+ "format" => "email"
416
+ },
417
+ "uuids" => {
418
+ "type" => "array",
419
+ "items" => {
420
+ "type" => "string",
421
+ "format" => "uuid"
422
+ }
423
+ }
424
+ },
425
+ "additionalProperties" => false
426
+ }
427
+ ```
428
+
277
429
  ### Versioning
278
430
 
279
431
  Verquest allows you to define multiple versions of your API requests, making it easy to evolve your API over time:
@@ -416,7 +568,7 @@ Verquest.configure do |config|
416
568
  config.current_version = -> { Current.api_version }
417
569
 
418
570
  # Set the JSON Schema version
419
- config.json_schema_version = :draft6 # default
571
+ config.json_schema_version = :draft2020_12 # default
420
572
 
421
573
  # Set the error handling strategy for processing params
422
574
  config.validation_error_handling = :raise # default, can be set also to :result
@@ -426,12 +578,15 @@ Verquest.configure do |config|
426
578
 
427
579
  # Set custom version resolver
428
580
  config.version_resolver = CustomeVersionResolver # default is `Verquest::VersionResolver`
581
+
582
+ # Set default value for additional properties
583
+ config.default_additional_properties = false # default
429
584
  end
430
585
  ```
431
586
 
432
587
  ## Documentation
433
588
 
434
- For detailed documentation, please visit the [YARD documentation](https://www.rubydoc.info/gems/verquest).
589
+ For detailed documentation, please visit the [YARD documentation](https://www.rubydoc.info/gems/verquest/0.5.0/).
435
590
 
436
591
  ## Development
437
592
 
@@ -92,9 +92,9 @@ module Verquest
92
92
  camelize(schema_options)
93
93
 
94
94
  if current_scope.nil?
95
- versions.schema_options = schema_options
95
+ versions.schema_options.merge!(schema_options)
96
96
  elsif current_scope.is_a?(Version)
97
- current_scope.schema_options = schema_options
97
+ current_scope.schema_options.merge!(schema_options)
98
98
  else
99
99
  raise "Additional properties can only be set within a version scope or globally"
100
100
  end
@@ -122,17 +122,19 @@ module Verquest
122
122
  # @param name [Symbol] The name of the field
123
123
  # @param type [Symbol] The data type of the field
124
124
  # @param map [String, nil] An optional mapping to another field
125
- # @param required [Boolean] Whether the field is required
125
+ # @param required [Boolean, Array<Symbol>] Whether the field is required
126
+ # @param nullable [Boolean] Whether the field can be null
126
127
  # @param schema_options [Hash] Additional schema options for the field
127
128
  # @return [void]
128
- def field(name, type: nil, map: nil, required: false, **schema_options)
129
+ def field(name, type: nil, map: nil, required: nil, nullable: nil, **schema_options)
129
130
  camelize(schema_options)
130
131
 
131
132
  type = default_options.fetch(:type, type)
132
- required = default_options.fetch(:required, required)
133
- schema_options = default_options.except(:type, :required).merge(schema_options)
133
+ required = default_options.fetch(:required, false) if required.nil?
134
+ nullable = default_options.fetch(:nullable, false) if nullable.nil?
135
+ schema_options = default_options.except(:type, :required, :nullable).merge(schema_options)
134
136
 
135
- field = Properties::Field.new(name:, type:, map:, required:, **schema_options)
137
+ field = Properties::Field.new(name:, type:, map:, required:, nullable:, **schema_options)
136
138
  current_scope.add(field)
137
139
  end
138
140
 
@@ -140,20 +142,22 @@ module Verquest
140
142
  #
141
143
  # @param name [Symbol] The name of the object
142
144
  # @param map [String, nil] An optional mapping to another object
143
- # @param required [Boolean] Whether the object is required
145
+ # @param required [Boolean, Array<Symbol>] Whether the object is required
146
+ # @param nullable [Boolean] Whether the object can be null
144
147
  # @param schema_options [Hash] Additional schema options for the object
145
148
  # @yield Block executed in the context of the new object definition
146
149
  # @return [void]
147
- def object(name, map: nil, required: false, **schema_options, &block)
150
+ def object(name, map: nil, required: nil, nullable: nil, **schema_options, &block)
148
151
  unless block_given?
149
152
  raise ArgumentError, "a block must be given to define the object"
150
153
  end
151
154
 
152
155
  camelize(schema_options)
153
- required = default_options.fetch(:required, required)
154
- schema_options = default_options.except(:type, :required).merge(schema_options)
156
+ required = default_options.fetch(:required, false) if required.nil?
157
+ nullable = default_options.fetch(:nullable, false) if nullable.nil?
158
+ schema_options = default_options.except(:type, :required, :nullable).merge(schema_options)
155
159
 
156
- object = Properties::Object.new(name:, map:, required:, **schema_options)
160
+ object = Properties::Object.new(name:, map:, required:, nullable:, **schema_options)
157
161
  current_scope.add(object)
158
162
 
159
163
  if block_given?
@@ -170,12 +174,13 @@ module Verquest
170
174
  #
171
175
  # @param name [Symbol] The name of the collection
172
176
  # @param item [Class, nil] The item type in the collection
173
- # @param required [Boolean] Whether the collection is required
177
+ # @param required [Boolean, Array<Symbol>] Whether the collection is required
178
+ # @param nullable [Boolean] Whether the collection can be null
174
179
  # @param map [String, nil] An optional mapping to another collection
175
180
  # @param schema_options [Hash] Additional schema options for the collection
176
181
  # @yield Block executed in the context of the new collection definition
177
182
  # @return [void]
178
- def collection(name, item: nil, required: false, map: nil, **schema_options, &block)
183
+ def collection(name, item: nil, required: nil, nullable: nil, map: nil, **schema_options, &block)
179
184
  if item.nil? && !block_given?
180
185
  raise ArgumentError, "item must be provided or a block must be given to define the collection"
181
186
  elsif !item.nil? && !block_given? && !(item <= Verquest::Base)
@@ -183,10 +188,11 @@ module Verquest
183
188
  end
184
189
 
185
190
  camelize(schema_options)
186
- required = default_options.fetch(:required, required)
187
- schema_options = default_options.except(:required).merge(schema_options)
191
+ required = default_options.fetch(:required, false) if required.nil?
192
+ nullable = default_options.fetch(:nullable, false) if nullable.nil?
193
+ schema_options = default_options.except(:required, :nullable).merge(schema_options)
188
194
 
189
- collection = Properties::Collection.new(name:, item:, required:, map:, **schema_options)
195
+ collection = Properties::Collection.new(name:, item:, required:, nullable:, map:, **schema_options)
190
196
  current_scope.add(collection)
191
197
 
192
198
  if block_given?
@@ -205,31 +211,35 @@ module Verquest
205
211
  # @param from [Verquest::Base] The source of the reference
206
212
  # @param property [Symbol, nil] An optional specific property to reference
207
213
  # @param map [String, nil] An optional mapping to another reference
208
- # @param required [Boolean] Whether the reference is required
214
+ # @param required [Boolean, Array<Symbol>] Whether the reference is required
215
+ # @param nullable [Boolean] Whether this reference can be null
209
216
  # @return [void]
210
- def reference(name, from:, property: nil, map: nil, required: false)
211
- required = default_options.fetch(:required, required)
217
+ def reference(name, from:, property: nil, map: nil, required: nil, nullable: nil)
218
+ required = default_options.fetch(:required, false) if required.nil?
219
+ nullable = default_options.fetch(:nullable, false) if nullable.nil?
212
220
 
213
- reference = Properties::Reference.new(name:, from:, property:, map:, required:)
221
+ reference = Properties::Reference.new(name:, from:, property:, map:, required:, nullable:)
214
222
  current_scope.add(reference)
215
223
  end
216
224
 
217
225
  # Defines a new array property for the current version scope
218
226
  #
219
227
  # @param name [Symbol] The name of the array property
220
- # @param type [String] The data type of the array elements
221
- # @param required [Boolean] Whether the array property is required
228
+ # @param type [Symbol] The data type of the array elements
229
+ # @param required [Boolean, Array<Symbol>] Whether the array property is required
230
+ # @param nullable [Boolean] Whether this array can be null
222
231
  # @param map [String, nil] An optional mapping to another array property
223
232
  # @param schema_options [Hash] Additional schema options for the array property
224
233
  # @return [void]
225
- def array(name, type:, required: false, map: nil, **schema_options)
234
+ def array(name, type:, required: nil, nullable: nil, map: nil, **schema_options)
226
235
  camelize(schema_options)
227
236
 
228
237
  type = default_options.fetch(:type, type)
229
- required = default_options.fetch(:required, required)
230
- schema_options = default_options.except(:type, :required).merge(schema_options)
238
+ required = default_options.fetch(:required, false) if required.nil?
239
+ nullable = default_options.fetch(:nullable, false) if nullable.nil?
240
+ schema_options = default_options.except(:type, :required, :nullable).merge(schema_options)
231
241
 
232
- array = Properties::Array.new(name:, type:, required:, map:, **schema_options)
242
+ array = Properties::Array.new(name:, type:, required:, nullable:, map:, **schema_options)
233
243
  current_scope.add(array)
234
244
  end
235
245
 
@@ -70,6 +70,19 @@ module Verquest
70
70
  #
71
71
  # @param version [String, nil] Specific version to use, defaults to configuration setting
72
72
  # @return [Boolean] True if schema is valid
73
+ def valid_schema?(version: nil)
74
+ resolve(version).valid_schema?
75
+ end
76
+
77
+ # Validates the schema against the metaschema and returns detailed validation errors
78
+ #
79
+ # This method validates the schema against the configured JSON Schema metaschema
80
+ # and returns detailed validation errors if any are found. It's useful for debugging
81
+ # schema issues during development and testing.
82
+ #
83
+ # @param version [String, nil] Specific version to use, defaults to configuration setting
84
+ # @return [Array<Hash>] An array of validation error details, empty if schema is valid
85
+ # @see #valid_schema?
73
86
  def validate_schema(version: nil)
74
87
  resolve(version).validate_schema
75
88
  end
@@ -11,6 +11,18 @@ module Verquest
11
11
  # config.current_version = -> { Current.api_version }
12
12
  # end
13
13
  class Configuration
14
+ include Base::HelperClassMethods
15
+
16
+ # Mapping of supported JSON Schema versions to their implementation classes
17
+ #
18
+ # This constant maps the symbolic names of JSON Schema versions to their
19
+ # corresponding JSONSchemer implementation classes. These are used for schema
20
+ # validation and generation based on the configured schema version.
21
+ #
22
+ # @example Accessing a schema implementation
23
+ # schema_class = Verquest::Configuration::SCHEMAS[:draft2020_12]
24
+ #
25
+ # @return [Hash<Symbol, Class>] A frozen hash mapping schema version names to implementation classes
14
26
  SCHEMAS = {
15
27
  draft4: JSONSchemer::Draft4,
16
28
  draft6: JSONSchemer::Draft6,
@@ -40,7 +52,12 @@ module Verquest
40
52
  # @!attribute [rw] insert_property_defaults
41
53
  # Controls whether default values defined in property schemas should be inserted when not provided during validation
42
54
  # @return [Boolean] true if default values should be inserted, false otherwise
43
- attr_accessor :validate_params, :json_schema_version, :validation_error_handling, :remove_extra_root_keys, :insert_property_defaults
55
+ #
56
+ # @!attribute [rw] default_additional_properties
57
+ # Controls the default behavior for handling properties not defined in the schema
58
+ # @return [Boolean] false to disallow additional properties (default), true to allow them
59
+ attr_accessor :validate_params, :json_schema_version, :validation_error_handling,
60
+ :remove_extra_root_keys, :insert_property_defaults, :default_additional_properties
44
61
 
45
62
  # @!attribute [r] current_version
46
63
  # A callable object that returns the current API version to use when not explicitly specified
@@ -49,7 +66,11 @@ module Verquest
49
66
  # @!attribute [r] version_resolver
50
67
  # The resolver used to map version strings/identifiers to version objects
51
68
  # @return [#call] An object that responds to `call` for resolving versions
52
- attr_reader :current_version, :version_resolver
69
+ #
70
+ # @!attribute [r] custom_field_types
71
+ # Custom field types to extend the standard set of field types
72
+ # @return [Hash<Symbol, Hash>] Hash mapping field type names to their configuration
73
+ attr_reader :current_version, :version_resolver, :custom_field_types
53
74
 
54
75
  # Initialize a new Configuration with default values
55
76
  #
@@ -57,10 +78,12 @@ module Verquest
57
78
  def initialize
58
79
  @validate_params = true
59
80
  @json_schema_version = :draft2020_12
60
- @validation_error_handling = :raise # or :result
81
+ @validation_error_handling = :raise
61
82
  @remove_extra_root_keys = true
62
83
  @version_resolver = VersionResolver
63
84
  @insert_property_defaults = true
85
+ @custom_field_types = {}
86
+ @default_additional_properties = false
64
87
  end
65
88
 
66
89
  # Sets the current version strategy using a callable object
@@ -85,6 +108,39 @@ module Verquest
85
108
  @version_resolver = version_resolver
86
109
  end
87
110
 
111
+ # Sets the custom field types
112
+ #
113
+ # This method allows defining custom field types beyond the default ones.
114
+ # Custom field types can be used to extend validation with specific formats
115
+ # or patterns. Each custom field type should include a base type and optional
116
+ # schema validation options.
117
+ #
118
+ # @example Adding a phone number field type
119
+ # config.custom_field_types = {
120
+ # email: {
121
+ # type: "string",
122
+ # schema_options: {format: "email", pattern: /\A[^@\s]+@[^@.\s]+(\.[^@.\s]+)+\z/}
123
+ # },
124
+ # uuid: {
125
+ # type: "string",
126
+ # schema_options: {format: "uuid", pattern: /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/}
127
+ # }
128
+ # }
129
+ #
130
+ # @param custom_field_types [Hash] A hash mapping field type names to their configuration
131
+ # @raise [ArgumentError] If the provided value isn't a Hash
132
+ # @return [Hash<Symbol, Hash>] The processed custom field types hash with symbolized keys
133
+ def custom_field_types=(custom_field_types)
134
+ raise ArgumentError, "Custom field types must be a Hash" unless custom_field_types.is_a?(Hash)
135
+
136
+ custom_field_types.delete_if { |k, _| Properties::Field::DEFAULT_TYPES.include?(k.to_s) }
137
+ custom_field_types.each do |_, value|
138
+ value[:schema_options] = camelize(value[:schema_options]) if value[:schema_options]
139
+ end
140
+
141
+ @custom_field_types = custom_field_types.transform_keys(&:to_sym)
142
+ end
143
+
88
144
  # Gets the JSON Schema class based on the configured version
89
145
  #
90
146
  # @return [Class] The JSON Schema class matching the configured version
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Verquest
4
- GEM_VERSION = "0.3.0"
4
+ GEM_VERSION = "0.5.0"
5
5
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Verquest
4
+ # HelperMethods module provides utility methods for Verquest
5
+ module HelperMethods
6
+ # Module that provides methods for working with required properties in schemas
7
+ #
8
+ # This module offers functionality to identify and categorize properties based on
9
+ # their required status within schema definitions. It distinguishes between
10
+ # unconditionally required properties (those marked with `required: true`) and
11
+ # conditionally required properties (those with dependencies expressed as arrays).
12
+ #
13
+ # When included in classes that manage properties (like Version or Base property classes),
14
+ # it provides methods to extract both types of required properties which can be used
15
+ # for schema validation, documentation generation, or UI rendering.
16
+ module RequiredProperties
17
+ # Returns all properties that are unconditionally required
18
+ #
19
+ # This method identifies properties that must always be present in valid data,
20
+ # by selecting those with their required attribute set to true (boolean).
21
+ # Results are memoized to avoid recalculating on subsequent calls.
22
+ #
23
+ # @return [Array<Symbol>] Names of properties marked as unconditionally required (required == true)
24
+ def required_properties
25
+ @_required_properties ||= properties.values.select { _1.required == true }.map(&:name)
26
+ end
27
+
28
+ # Returns properties that are conditionally required based on other properties
29
+ #
30
+ # This method identifies properties that are required only when certain other
31
+ # properties are present. These are properties where the required attribute
32
+ # is an array of dependency names rather than a boolean.
33
+ # Results are memoized to avoid recalculating on subsequent calls.
34
+ #
35
+ # @return [Hash<String, Array<String>>] Hash mapping property names to their dependency arrays
36
+ # @example Return value format:
37
+ # {
38
+ # "property_name1": ["dependency1", "dependency2"],
39
+ # "property_name2": ["dependency3"]
40
+ # }
41
+ def dependent_required_properties
42
+ @_dependent_required_properties ||= properties.values.select { _1.required.is_a?(Array) }.each_with_object({}) do |property, hash|
43
+ hash[property.name] = property.required.map(&:to_s)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -6,6 +6,7 @@ module Verquest
6
6
  #
7
7
  # Represents an array data structure in the schema with specified item type.
8
8
  # Used to define arrays of scalar types (string, number, integer, boolean).
9
+ # Supports both default item types and custom field types defined in the configuration.
9
10
  #
10
11
  # @example Define an array of strings
11
12
  # array = Verquest::Properties::Array.new(
@@ -17,19 +18,41 @@ module Verquest
17
18
  # Initialize a new Array property
18
19
  #
19
20
  # @param name [String, Symbol] The name of the property
20
- # @param type [String, Symbol] The type of items in the array
21
+ # @param type [String, Symbol] The type of items in the array, can be a default type or a custom field type
21
22
  # @param map [String, nil] The mapping path for this property (nil for no explicit mapping)
22
- # @param required [Boolean] Whether this property is required
23
- # @param schema_options [Hash] Additional JSON schema options for this property
23
+ # @param required [Boolean, Array<Symbol>] Whether this property is required, or array of dependency names
24
+ # @param nullable [Boolean] Whether this property can be null
25
+ # @param item_schema_options [Hash] Additional JSON schema options for the array items (merged with custom type options)
26
+ # @param schema_options [Hash] Additional JSON schema options for the array property itself
27
+ # @raise [ArgumentError] If type is not one of the allowed types (default or custom)
24
28
  # @raise [ArgumentError] If attempting to map an array to the root
25
- def initialize(name:, type:, map: nil, required: false, **schema_options)
29
+ def initialize(name:, type:, map: nil, required: false, nullable: false, item_schema_options: {}, **schema_options)
30
+ raise ArgumentError, "Type must be one of #{allowed_types.join(", ")}" unless allowed_types.include?(type.to_s)
26
31
  raise ArgumentError, "You can not map array to the root" if map == "/"
27
32
 
33
+ if (custom_type = Verquest.configuration.custom_field_types[type.to_sym])
34
+ @item_type = custom_type[:type].to_s
35
+ @item_schema_options = if custom_type.key?(:schema_options)
36
+ custom_type[:schema_options].merge(item_schema_options).transform_keys(&:to_s)
37
+ else
38
+ item_schema_options.transform_keys(&:to_s)
39
+ end
40
+ else
41
+ @item_type = type.to_s
42
+ @item_schema_options = item_schema_options.transform_keys(&:to_s)
43
+ end
44
+
28
45
  @name = name.to_s
29
- @type = type.to_s
30
46
  @map = map
31
47
  @required = required
48
+ @nullable = nullable
32
49
  @schema_options = schema_options&.transform_keys(&:to_s)
50
+
51
+ @type = if nullable
52
+ %w[array null]
53
+ else
54
+ "array"
55
+ end
33
56
  end
34
57
 
35
58
  # Generate JSON schema definition for this array property
@@ -38,8 +61,8 @@ module Verquest
38
61
  def to_schema
39
62
  {
40
63
  name => {
41
- "type" => "array",
42
- "items" => {"type" => type}
64
+ "type" => type,
65
+ "items" => {"type" => item_type}.merge(item_schema_options)
43
66
  }.merge(schema_options)
44
67
  }
45
68
  end
@@ -57,7 +80,14 @@ module Verquest
57
80
 
58
81
  private
59
82
 
60
- attr_reader :type, :schema_options
83
+ attr_reader :type, :item_type, :schema_options, :item_schema_options
84
+
85
+ # Gets the list of allowed item types, including both default and custom types
86
+ #
87
+ # @return [Array<String>] Array of allowed item type names
88
+ def allowed_types
89
+ Verquest::Properties::Field::DEFAULT_TYPES + Verquest.configuration.custom_field_types.keys.map(&:to_s)
90
+ end
61
91
  end
62
92
  end
63
93
  end
@@ -10,6 +10,8 @@ module Verquest
10
10
  #
11
11
  # @abstract Subclass and override {#to_schema}, {#mapping} to implement
12
12
  class Base
13
+ include HelperMethods::RequiredProperties
14
+
13
15
  # @!attribute [rw] name
14
16
  # @return [String] The name of the property
15
17
  # @!attribute [rw] required
@@ -55,6 +57,10 @@ module Verquest
55
57
 
56
58
  private
57
59
 
60
+ # @!attribute [r] nullable
61
+ # @return [Boolean] Whether this property can be null
62
+ attr_reader :nullable
63
+
58
64
  # Determines the mapping target key based on mapping configuration
59
65
  # @param value_prefix [Array<String>] Prefix for the target value
60
66
  # @param collection [Boolean] Whether this is a collection mapping
@@ -22,11 +22,12 @@ module Verquest
22
22
  #
23
23
  # @param name [String, Symbol] The name of the property
24
24
  # @param item [Verquest::Base, nil] Optional reference to an external schema class
25
- # @param required [Boolean] Whether this property is required
25
+ # @param required [Boolean, Array<Symbol>] Whether this property is required, or array of dependency names
26
+ # @param nullable [Boolean] Whether this property can be null
26
27
  # @param map [String, nil] The mapping path for this property
27
28
  # @param schema_options [Hash] Additional JSON schema options for this property
28
29
  # @raise [ArgumentError] If attempting to map a collection to the root
29
- def initialize(name:, item: nil, required: false, map: nil, **schema_options)
30
+ def initialize(name:, item: nil, required: false, nullable: false, map: nil, **schema_options)
30
31
  raise ArgumentError, "You can not map collection to the root" if map == "/"
31
32
 
32
33
  @properties = {}
@@ -34,8 +35,15 @@ module Verquest
34
35
  @name = name.to_s
35
36
  @item = item
36
37
  @required = required
38
+ @nullable = nullable
37
39
  @map = map
38
40
  @schema_options = schema_options&.transform_keys(&:to_s)
41
+
42
+ @type = if nullable
43
+ %w[array null]
44
+ else
45
+ "array"
46
+ end
39
47
  end
40
48
 
41
49
  # Add a child property to this collection's item definition
@@ -60,7 +68,7 @@ module Verquest
60
68
  if has_item?
61
69
  {
62
70
  name => {
63
- "type" => "array",
71
+ "type" => type,
64
72
  "items" => {
65
73
  "$ref" => item.to_ref
66
74
  }
@@ -69,12 +77,15 @@ module Verquest
69
77
  else
70
78
  {
71
79
  name => {
72
- "type" => "array",
80
+ "type" => type,
73
81
  "items" => {
74
82
  "type" => "object",
75
- "required" => properties.values.select(&:required).map(&:name),
76
- "properties" => properties.transform_values { |property| property.to_schema[property.name] }
77
- }
83
+ "required" => required_properties,
84
+ "properties" => properties.transform_values { |property| property.to_schema[property.name] },
85
+ "additionalProperties" => Verquest.configuration.default_additional_properties
86
+ }.tap do |schema|
87
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
88
+ end
78
89
  }.merge(schema_options)
79
90
  }
80
91
  end
@@ -88,19 +99,22 @@ module Verquest
88
99
  if has_item?
89
100
  {
90
101
  name => {
91
- "type" => "array",
102
+ "type" => type,
92
103
  "items" => item.to_validation_schema(version: version)
93
104
  }.merge(schema_options)
94
105
  }
95
106
  else
96
107
  {
97
108
  name => {
98
- "type" => "array",
109
+ "type" => type,
99
110
  "items" => {
100
111
  "type" => "object",
101
- "required" => properties.values.select(&:required).map(&:name),
102
- "properties" => properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] }
103
- }
112
+ "required" => required_properties,
113
+ "properties" => properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] },
114
+ "additionalProperties" => Verquest.configuration.default_additional_properties
115
+ }.tap do |schema|
116
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
117
+ end
104
118
  }.merge(schema_options)
105
119
  }
106
120
  end
@@ -141,7 +155,7 @@ module Verquest
141
155
 
142
156
  private
143
157
 
144
- attr_reader :item, :schema_options, :properties
158
+ attr_reader :item, :schema_options, :properties, :type
145
159
  end
146
160
  end
147
161
  end
@@ -6,6 +6,7 @@ module Verquest
6
6
  #
7
7
  # Represents simple scalar types (string, number, integer, boolean) in the schema.
8
8
  # Used for defining basic data fields without nesting.
9
+ # Supports both default types and custom field types defined in the configuration.
9
10
  #
10
11
  # @example Define a required string field
11
12
  # field = Verquest::Properties::Field.new(
@@ -15,35 +16,54 @@ module Verquest
15
16
  # format: "email"
16
17
  # )
17
18
  class Field < Base
18
- # List of allowed field types
19
+ # List of default field types
19
20
  # @return [Array<Symbol>]
20
- ALLOWED_TYPES = %w[string number integer boolean].freeze
21
+ DEFAULT_TYPES = %w[string number integer boolean].freeze
21
22
 
22
23
  # Initialize a new Field property
23
24
  #
24
25
  # @param name [String, Symbol] The name of the property
25
- # @param type [String, Symbol] The data type for this field, must be one of ALLOWED_TYPES
26
- # @param required [Boolean] Whether this property is required
26
+ # @param type [String, Symbol] The data type for this field, can be a default type or a custom field type
27
+ # @param required [Boolean, Array<Symbol>] Whether this property is required, or array of dependency names (can be overridden by custom type)
28
+ # @param nullable [Boolean] Whether this property can be null
27
29
  # @param map [String, nil] The mapping path for this property
28
- # @param schema_options [Hash] Additional JSON schema options for this property
29
- # @raise [ArgumentError] If type is not one of the allowed types
30
+ # @param schema_options [Hash] Additional JSON schema options for this property (merged with custom type options)
31
+ # @raise [ArgumentError] If type is not one of the allowed types (default or custom)
30
32
  # @raise [ArgumentError] If attempting to map a field to root without a name
31
- def initialize(name:, type:, required: false, map: nil, **schema_options)
32
- raise ArgumentError, "Type must be one of #{ALLOWED_TYPES.join(", ")}" unless ALLOWED_TYPES.include?(type.to_s)
33
+ def initialize(name:, type:, required: false, nullable: false, map: nil, **schema_options)
34
+ raise ArgumentError, "Type must be one of #{allowed_types.join(", ")}" unless allowed_types.include?(type.to_s)
33
35
  raise ArgumentError, "You can not map fields to the root without a name" if map == "/"
34
36
 
37
+ if (custom_type = Verquest.configuration.custom_field_types[type.to_sym])
38
+ @type = custom_type[:type].to_s
39
+ @required = custom_type.key?(:required) ? custom_type[:required] : required
40
+ @schema_options = if custom_type.key?(:schema_options)
41
+ custom_type[:schema_options].merge(schema_options).transform_keys(&:to_s)
42
+ else
43
+ schema_options.transform_keys(&:to_s)
44
+ end
45
+ else
46
+ @type = type.to_s
47
+ @required = required
48
+ @schema_options = schema_options&.transform_keys(&:to_s)
49
+ end
50
+
35
51
  @name = name.to_s
36
- @type = type.to_s
37
- @required = required
52
+ @nullable = nullable
38
53
  @map = map
39
- @schema_options = schema_options&.transform_keys(&:to_s)
54
+
55
+ if nullable
56
+ @type = [@type, "null"]
57
+ end
40
58
  end
41
59
 
42
60
  # Generate JSON schema definition for this field
43
61
  #
44
62
  # @return [Hash] The schema definition for this field
45
63
  def to_schema
46
- {name => {"type" => type}.merge(schema_options)}
64
+ {
65
+ name => {"type" => type}.merge(schema_options)
66
+ }
47
67
  end
48
68
 
49
69
  # Create mapping for this field property
@@ -60,6 +80,13 @@ module Verquest
60
80
  private
61
81
 
62
82
  attr_reader :type, :schema_options
83
+
84
+ # Gets the list of allowed field types, including both default and custom types
85
+ #
86
+ # @return [Array<String>] Array of allowed field type names
87
+ def allowed_types
88
+ DEFAULT_TYPES + Verquest.configuration.custom_field_types.keys.map(&:to_s)
89
+ end
63
90
  end
64
91
  end
65
92
  end
@@ -15,16 +15,28 @@ module Verquest
15
15
  # Initialize a new Object property
16
16
  #
17
17
  # @param name [String, Symbol] The name of the property
18
- # @param required [Boolean] Whether this property is required
18
+ # @param required [Boolean, Array<Symbol>] Whether this property is required, or array of dependency names
19
+ # @param nullable [Boolean] Whether this property can be null
19
20
  # @param map [String, nil] The mapping path for this property
20
21
  # @param schema_options [Hash] Additional JSON schema options for this property
21
- def initialize(name:, required: false, map: nil, **schema_options)
22
+ def initialize(name:, required: false, nullable: false, map: nil, **schema_options)
22
23
  @properties = {}
23
24
 
24
25
  @name = name.to_s
25
26
  @required = required
27
+ @nullable = nullable
26
28
  @map = map
27
- @schema_options = schema_options&.transform_keys(&:to_s)
29
+ @schema_options = {
30
+ additionalProperties: Verquest.configuration.default_additional_properties
31
+ }.merge(schema_options)
32
+ .delete_if { |_, v| v.nil? }
33
+ .transform_keys(&:to_s)
34
+
35
+ @type = if nullable
36
+ %w[object null]
37
+ else
38
+ "object"
39
+ end
28
40
  end
29
41
 
30
42
  # Add a child property to this object
@@ -41,10 +53,12 @@ module Verquest
41
53
  def to_schema
42
54
  {
43
55
  name => {
44
- "type" => "object",
45
- "required" => properties.values.select(&:required).map(&:name),
56
+ "type" => type,
57
+ "required" => required_properties,
46
58
  "properties" => properties.transform_values { |property| property.to_schema[property.name] }
47
- }.merge(schema_options)
59
+ }.merge(schema_options).tap do |schema|
60
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
61
+ end
48
62
  }
49
63
  end
50
64
 
@@ -55,10 +69,12 @@ module Verquest
55
69
  def to_validation_schema(version: nil)
56
70
  {
57
71
  name => {
58
- "type" => "object",
59
- "required" => properties.values.select(&:required).map(&:name),
72
+ "type" => type,
73
+ "required" => required_properties,
60
74
  "properties" => properties.transform_values { |property| property.to_validation_schema(version: version)[property.name] }
61
- }.merge(schema_options)
75
+ }.merge(schema_options).tap do |schema|
76
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
77
+ end
62
78
  }
63
79
  end
64
80
 
@@ -26,12 +26,14 @@ module Verquest
26
26
  # @param name [String, Symbol] The name of the property
27
27
  # @param from [Class] The schema class to reference
28
28
  # @param property [Symbol, nil] Optional specific property to reference
29
+ # @param nullable [Boolean] Whether this property can be null
29
30
  # @param map [String, nil] The mapping path for this property
30
- # @param required [Boolean] Whether this property is required
31
- def initialize(name:, from:, property: nil, map: nil, required: false)
31
+ # @param required [Boolean, Array<Symbol>] Whether this property is required, or array of dependency names
32
+ def initialize(name:, from:, property: nil, nullable: false, map: nil, required: false)
32
33
  @name = name.to_s
33
34
  @from = from
34
35
  @property = property
36
+ @nullable = nullable
35
37
  @map = map
36
38
  @required = required
37
39
  end
@@ -40,9 +42,20 @@ module Verquest
40
42
  #
41
43
  # @return [Hash] The schema definition with a $ref pointer
42
44
  def to_schema
43
- {
44
- name => {"$ref" => from.to_ref(property: property)}
45
- }
45
+ if nullable
46
+ {
47
+ name => {
48
+ "oneOf" => [
49
+ {"$ref" => from.to_ref(property: property)},
50
+ {"type" => "null"}
51
+ ]
52
+ }
53
+ }
54
+ else
55
+ {
56
+ name => {"$ref" => from.to_ref(property: property)}
57
+ }
58
+ end
46
59
  end
47
60
 
48
61
  # Generate validation schema for this reference property
@@ -50,8 +63,14 @@ module Verquest
50
63
  # @param version [String, nil] The version to generate validation schema for
51
64
  # @return [Hash] The validation schema for this reference
52
65
  def to_validation_schema(version: nil)
66
+ schema = from.to_validation_schema(version:, property: property).dup
67
+
68
+ if nullable
69
+ schema["type"] = [schema["type"], "null"] unless schema["type"].include?("null")
70
+ end
71
+
53
72
  {
54
- name => from.to_validation_schema(version:, property: property)
73
+ name => schema
55
74
  }
56
75
  end
57
76
 
@@ -19,6 +19,8 @@ module Verquest
19
19
  # # Get mapping
20
20
  # mapping = version.mapping
21
21
  class Version
22
+ include HelperMethods::RequiredProperties
23
+
22
24
  # @!attribute [r] name
23
25
  # @return [String] The name/identifier of the version (e.g., "2023-01")
24
26
  #
@@ -102,6 +104,12 @@ module Verquest
102
104
  def prepare
103
105
  return if frozen?
104
106
 
107
+ unless schema_options.key?("additionalProperties")
108
+ schema_options["additionalProperties"] = Verquest.configuration.default_additional_properties
109
+ end
110
+
111
+ schema_options.delete_if { |_, v| v.nil? }
112
+
105
113
  prepare_schema
106
114
  prepare_validation_schema
107
115
  prepare_mapping
@@ -113,11 +121,33 @@ module Verquest
113
121
  # Validate the schema against the metaschema
114
122
  #
115
123
  # @return [Boolean] true if the schema is valid, false otherwise
124
+ def valid_schema?
125
+ JSONSchemer.valid_schema?(
126
+ validation_schema,
127
+ meta_schema: Verquest.configuration.json_schema_uri
128
+ )
129
+ end
130
+
131
+ # Validate the schema against the metaschema and return detailed errors
132
+ #
133
+ # This method validates the schema against the configured JSON Schema metaschema
134
+ # and returns detailed validation errors if any are found. It uses the JSONSchemer
135
+ # library with the schema version specified in the configuration.
136
+ #
137
+ # @return [Array<Hash>] An array of validation error details, empty if schema is valid
138
+ # @see #valid_schema?
116
139
  def validate_schema
117
140
  JSONSchemer.validate_schema(
118
141
  validation_schema,
119
142
  meta_schema: Verquest.configuration.json_schema_uri
120
- )
143
+ ).map do |error|
144
+ {
145
+ pointer: error["data_pointer"],
146
+ type: error["type"],
147
+ message: error["error"],
148
+ details: error["details"]
149
+ }
150
+ end
121
151
  end
122
152
 
123
153
  # Validate request parameters against the version's validation schema
@@ -175,9 +205,11 @@ module Verquest
175
205
  @schema = {
176
206
  "type" => "object",
177
207
  "description" => description,
178
- "required" => properties.values.select(&:required).map(&:name),
208
+ "required" => required_properties,
179
209
  "properties" => properties.transform_values { |property| property.to_schema[property.name] }
180
- }.merge(schema_options).freeze
210
+ }.merge(schema_options).tap do |schema|
211
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
212
+ end.freeze
181
213
  end
182
214
 
183
215
  # Generates the validation schema for this version
@@ -190,9 +222,11 @@ module Verquest
190
222
  @validation_schema = {
191
223
  "type" => "object",
192
224
  "description" => description,
193
- "required" => properties.values.select(&:required).map(&:name),
225
+ "required" => required_properties,
194
226
  "properties" => properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
195
- }.merge(schema_options).freeze
227
+ }.merge(schema_options).tap do |schema|
228
+ schema["dependentRequired"] = dependent_required_properties if dependent_required_properties.any?
229
+ end.freeze
196
230
  end
197
231
 
198
232
  # Prepares the parameter mapping for this version
data/lib/verquest.rb CHANGED
@@ -3,8 +3,11 @@
3
3
  require "zeitwerk"
4
4
  require "json_schemer"
5
5
 
6
+ require_relative "verquest/gem_version"
7
+
6
8
  loader = Zeitwerk::Loader.new
7
9
  loader.tag = File.basename(__FILE__, ".rb")
10
+ loader.ignore("#{File.dirname(__FILE__)}/verquest/gem_version.rb")
8
11
  loader.push_dir(File.dirname(__FILE__))
9
12
  loader.setup
10
13
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: verquest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Hlavicka
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-06-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: zeitwerk
@@ -62,6 +61,7 @@ files:
62
61
  - lib/verquest/base/public_class_methods.rb
63
62
  - lib/verquest/configuration.rb
64
63
  - lib/verquest/gem_version.rb
64
+ - lib/verquest/helper_methods/required_properties.rb
65
65
  - lib/verquest/properties.rb
66
66
  - lib/verquest/properties/array.rb
67
67
  - lib/verquest/properties/base.rb
@@ -81,7 +81,6 @@ metadata:
81
81
  homepage_uri: https://github.com/CiTroNaK/verquest
82
82
  source_code_uri: https://github.com/CiTroNaK/verquest
83
83
  changelog_uri: https://github.com/CiTroNaK/verquest/blob/main/CHANGELOG.md
84
- post_install_message:
85
84
  rdoc_options: []
86
85
  require_paths:
87
86
  - lib
@@ -96,8 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
95
  - !ruby/object:Gem::Version
97
96
  version: '0'
98
97
  requirements: []
99
- rubygems_version: 3.4.19
100
- signing_key:
98
+ rubygems_version: 3.6.9
101
99
  specification_version: 4
102
100
  summary: Verquest is a Ruby gem that offers an elegant solution for versioning API
103
101
  requests