verquest 0.6.2 → 0.6.3
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/CHANGELOG.md +5 -0
- data/Rakefile +26 -3
- data/lib/verquest/base/private_class_methods.rb +30 -0
- data/lib/verquest/base/public_class_methods.rb +18 -9
- data/lib/verquest/configuration.rb +2 -0
- data/lib/verquest/gem_version.rb +1 -1
- data/lib/verquest/helper_methods/required_properties.rb +1 -1
- data/lib/verquest/properties/array.rb +2 -2
- data/lib/verquest/properties/base.rb +1 -1
- data/lib/verquest/properties/collection.rb +44 -5
- data/lib/verquest/properties/const.rb +2 -2
- data/lib/verquest/properties/enum.rb +2 -2
- data/lib/verquest/properties/field.rb +2 -2
- data/lib/verquest/properties/object.rb +1 -1
- data/lib/verquest/properties/one_of.rb +437 -0
- data/lib/verquest/properties/reference.rb +2 -2
- data/lib/verquest/transformer.rb +813 -48
- data/lib/verquest/version.rb +240 -11
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f02a2f54e2736694e9f26f4c4b2fd2d2939fb246b3bd9031733e6bf606fac3f0
|
|
4
|
+
data.tar.gz: 0ca7bd1d066426f72a8507cb25dcda7f45df491dedfd8ee4b0be9e425df5c528
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68bb809fe32619ff5bf02f43787cee0d36f6462c1fb84114b246e8165c6c8725d1fd05048cd788d5c9eb97d89b60cc9dc91c008b81ad1240d80dd3dc62cf1843
|
|
7
|
+
data.tar.gz: 59471fdfdfb8aaca008467e772d925520fd1b491ce9e303b987bc96f4c2d119f37517cc819c5506de17b2839c3f386827fc5408cfa9fa694b4250642dbd1d6a2
|
data/CHANGELOG.md
CHANGED
data/Rakefile
CHANGED
|
@@ -1,12 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
|
-
require "
|
|
4
|
+
require "rake/testtask"
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "test"
|
|
8
|
+
t.libs << "lib"
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
+
t.warning = true
|
|
11
|
+
end
|
|
7
12
|
|
|
8
13
|
require "rubocop/rake_task"
|
|
9
14
|
|
|
10
15
|
RuboCop::RakeTask.new
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
desc "Check YARD documentation coverage (must be 100%)"
|
|
18
|
+
task :yard do
|
|
19
|
+
require "yard"
|
|
20
|
+
|
|
21
|
+
# Capture the stats output
|
|
22
|
+
stats = YARD::CLI::Stats.new
|
|
23
|
+
stats.run("--list-undoc")
|
|
24
|
+
|
|
25
|
+
# Check if there are any undocumented objects
|
|
26
|
+
undocumented = stats.instance_variable_get(:@undoc_list) || []
|
|
27
|
+
|
|
28
|
+
unless undocumented.empty?
|
|
29
|
+
abort "\nYARD documentation check failed: #{undocumented.size} undocumented objects found."
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
puts "\nYARD documentation: 100% documented"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
task default: %i[test rubocop yard]
|
|
@@ -280,6 +280,36 @@ module Verquest
|
|
|
280
280
|
current_scope.add(array)
|
|
281
281
|
end
|
|
282
282
|
|
|
283
|
+
# Defines a oneOf property for polymorphic schemas
|
|
284
|
+
#
|
|
285
|
+
# Creates a JSON Schema oneOf structure where exactly one of the defined
|
|
286
|
+
# schemas must match. When used at the root level (without a name), it creates
|
|
287
|
+
# a "combination schema" where the entire request body matches one of the options.
|
|
288
|
+
#
|
|
289
|
+
# @param name [Symbol, nil] The property name, or nil for root-level oneOf
|
|
290
|
+
# @param discriminator [Symbol, nil] The property used to discriminate between schemas
|
|
291
|
+
# @param required [Boolean, Array<Symbol>, nil] Whether this property is required
|
|
292
|
+
# @param nullable [Boolean] Whether this property can be null
|
|
293
|
+
# @param map [String, nil] An optional mapping to another property
|
|
294
|
+
# @yield Block defining the schema options using reference declarations
|
|
295
|
+
# @return [void]
|
|
296
|
+
def one_of(name: nil, discriminator: nil, required: nil, nullable: nil, map: nil, &block)
|
|
297
|
+
required = default_options.fetch(:required, false) if required.nil?
|
|
298
|
+
nullable = default_options.fetch(:nullable, false) if nullable.nil?
|
|
299
|
+
|
|
300
|
+
one_of = Properties::OneOf.new(name:, discriminator:, required:, nullable:, map:)
|
|
301
|
+
current_scope.add(one_of)
|
|
302
|
+
|
|
303
|
+
if block_given?
|
|
304
|
+
previous_scope = current_scope
|
|
305
|
+
@current_scope = one_of
|
|
306
|
+
|
|
307
|
+
instance_exec(&block)
|
|
308
|
+
end
|
|
309
|
+
ensure
|
|
310
|
+
@current_scope = previous_scope if block_given?
|
|
311
|
+
end
|
|
312
|
+
|
|
283
313
|
# Excludes specified properties from the current scope by removing them
|
|
284
314
|
# from the version's property set
|
|
285
315
|
#
|
|
@@ -12,7 +12,7 @@ module Verquest
|
|
|
12
12
|
# @param version [String, nil] Specific version to use, defaults to configuration setting
|
|
13
13
|
# @param validate [Boolean, nil] Whether to validate the params, defaults to configuration setting
|
|
14
14
|
# @param remove_extra_root_keys [Boolean, nil] Whether to remove extra keys at the root level, defaults to configuration setting
|
|
15
|
-
# @return [Verquest::Result, Hash
|
|
15
|
+
# @return [Verquest::Result, Hash] When validation_error_handling is :result, returns a Success result with mapped params or Failure result with validation errors.
|
|
16
16
|
# When validation_error_handling is :raise, returns mapped params directly or raises InvalidParamsError with validation errors.
|
|
17
17
|
def process(params, version: nil, validate: nil, remove_extra_root_keys: nil)
|
|
18
18
|
validate = Verquest.configuration.validate_params if validate.nil?
|
|
@@ -22,7 +22,7 @@ module Verquest
|
|
|
22
22
|
|
|
23
23
|
params = params.dup
|
|
24
24
|
params = params.to_unsafe_h if params.respond_to?(:to_unsafe_h)
|
|
25
|
-
params = params.slice(*version_class.properties.keys) if remove_extra_root_keys
|
|
25
|
+
params = params.slice(*version_class.properties.keys) if remove_extra_root_keys && !version_class.combination?
|
|
26
26
|
|
|
27
27
|
if validate && (validation_result = version_class.validate_params(params: params)) && validation_result.any?
|
|
28
28
|
case Verquest.configuration.validation_error_handling
|
|
@@ -32,13 +32,22 @@ module Verquest
|
|
|
32
32
|
Result.failure(validation_result)
|
|
33
33
|
end
|
|
34
34
|
else
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
35
|
+
begin
|
|
36
|
+
mapped_params = version_class.map_params(params)
|
|
37
|
+
|
|
38
|
+
case Verquest.configuration.validation_error_handling
|
|
39
|
+
when :raise
|
|
40
|
+
mapped_params
|
|
41
|
+
when :result
|
|
42
|
+
Result.success(mapped_params)
|
|
43
|
+
end
|
|
44
|
+
rescue MappingError => e
|
|
45
|
+
case Verquest.configuration.validation_error_handling
|
|
46
|
+
when :raise
|
|
47
|
+
raise
|
|
48
|
+
when :result
|
|
49
|
+
Result.failure([{message: e.message, type: "mapping_error"}])
|
|
50
|
+
end
|
|
42
51
|
end
|
|
43
52
|
end
|
|
44
53
|
end
|
data/lib/verquest/gem_version.rb
CHANGED
|
@@ -20,7 +20,7 @@ module Verquest
|
|
|
20
20
|
# by selecting those with their required attribute set to true (boolean).
|
|
21
21
|
# Results are memoized to avoid recalculating on subsequent calls.
|
|
22
22
|
#
|
|
23
|
-
# @return [Array<
|
|
23
|
+
# @return [Array<String>] Names of properties marked as unconditionally required (required == true)
|
|
24
24
|
def required_properties
|
|
25
25
|
@_required_properties ||= properties.values.select { _1.required == true }.map(&:name)
|
|
26
26
|
end
|
|
@@ -72,8 +72,8 @@ module Verquest
|
|
|
72
72
|
# @param key_prefix [Array<String>] Prefix for the source key
|
|
73
73
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
74
74
|
# @param mapping [Hash] The mapping hash to be updated
|
|
75
|
-
# @param version [String, nil] The version to create mapping for
|
|
76
|
-
# @return [
|
|
75
|
+
# @param version [String, nil] The version to create mapping for
|
|
76
|
+
# @return [void]
|
|
77
77
|
def mapping(key_prefix:, value_prefix:, mapping:, version: nil)
|
|
78
78
|
mapping[(key_prefix + [name]).join("/")] = mapping_value_key(value_prefix:)
|
|
79
79
|
end
|
|
@@ -49,7 +49,7 @@ module Verquest
|
|
|
49
49
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
50
50
|
# @param mapping [Hash] The mapping hash to be updated
|
|
51
51
|
# @param version [String, nil] The version to create mapping for
|
|
52
|
-
# @return [
|
|
52
|
+
# @return [void]
|
|
53
53
|
# @raise [NoMethodError] This is an abstract method that must be overridden
|
|
54
54
|
def mapping(key_prefix:, value_prefix:, mapping:, version:)
|
|
55
55
|
raise NoMethodError
|
|
@@ -61,6 +61,22 @@ module Verquest
|
|
|
61
61
|
!item.nil?
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# Check if this collection contains a oneOf property as its item type
|
|
65
|
+
#
|
|
66
|
+
# @return [Boolean] True if the collection contains a oneOf property
|
|
67
|
+
def has_one_of?
|
|
68
|
+
properties.values.size == 1 && properties.values.first.is_a?(Verquest::Properties::OneOf)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Returns the oneOf property if this collection contains one
|
|
72
|
+
#
|
|
73
|
+
# @return [Verquest::Properties::OneOf, nil] The oneOf property or nil
|
|
74
|
+
def one_of_property
|
|
75
|
+
return nil unless has_one_of?
|
|
76
|
+
|
|
77
|
+
properties.values.first
|
|
78
|
+
end
|
|
79
|
+
|
|
64
80
|
# Generate JSON schema definition for this collection property
|
|
65
81
|
#
|
|
66
82
|
# @return [Hash] The schema definition for this collection property
|
|
@@ -74,6 +90,13 @@ module Verquest
|
|
|
74
90
|
}
|
|
75
91
|
}.merge(schema_options)
|
|
76
92
|
}
|
|
93
|
+
elsif has_one_of?
|
|
94
|
+
{
|
|
95
|
+
name => {
|
|
96
|
+
"type" => type,
|
|
97
|
+
"items" => one_of_property.to_schema[one_of_property.name] || one_of_property.to_schema
|
|
98
|
+
}.merge(schema_options)
|
|
99
|
+
}
|
|
77
100
|
else
|
|
78
101
|
{
|
|
79
102
|
name => {
|
|
@@ -103,6 +126,14 @@ module Verquest
|
|
|
103
126
|
"items" => item.to_validation_schema(version: version)
|
|
104
127
|
}.merge(schema_options)
|
|
105
128
|
}
|
|
129
|
+
elsif has_one_of?
|
|
130
|
+
one_of_schema = one_of_property.to_validation_schema(version: version)
|
|
131
|
+
{
|
|
132
|
+
name => {
|
|
133
|
+
"type" => type,
|
|
134
|
+
"items" => one_of_schema[one_of_property.name] || one_of_schema
|
|
135
|
+
}.merge(schema_options)
|
|
136
|
+
}
|
|
106
137
|
else
|
|
107
138
|
{
|
|
108
139
|
name => {
|
|
@@ -122,13 +153,17 @@ module Verquest
|
|
|
122
153
|
|
|
123
154
|
# Create mapping for this collection property and all its children
|
|
124
155
|
#
|
|
125
|
-
# This method handles
|
|
156
|
+
# This method handles three different scenarios:
|
|
126
157
|
# 1. When the collection references an external item schema (`has_item?` returns true)
|
|
127
158
|
# - Creates mappings by transforming keys from the referenced item schema
|
|
128
159
|
# - Adds array notation ([]) to indicate this is a collection
|
|
129
160
|
# - Prefixes all keys and values with the appropriate paths
|
|
130
161
|
#
|
|
131
|
-
# 2. When the collection
|
|
162
|
+
# 2. When the collection contains a oneOf property (`has_one_of?` returns true)
|
|
163
|
+
# - Creates variant-keyed mappings for discriminator-less oneOf support
|
|
164
|
+
# - Each variant gets array notation applied to its paths
|
|
165
|
+
#
|
|
166
|
+
# 3. When the collection has inline item properties
|
|
132
167
|
# - Creates mappings for each property in the collection items
|
|
133
168
|
# - Each property gets mapped with array notation and appropriate prefixes
|
|
134
169
|
#
|
|
@@ -136,16 +171,20 @@ module Verquest
|
|
|
136
171
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
137
172
|
# @param mapping [Hash] The mapping hash to be updated
|
|
138
173
|
# @param version [String, nil] The version to create mapping for
|
|
139
|
-
# @return [
|
|
174
|
+
# @return [void]
|
|
140
175
|
def mapping(key_prefix:, value_prefix:, mapping:, version:)
|
|
141
176
|
if has_item?
|
|
142
177
|
value_key_prefix = mapping_value_key(value_prefix: value_prefix, collection: true)
|
|
143
178
|
|
|
144
179
|
reference_mapping = item.mapping(version:).dup
|
|
145
|
-
reference_mapping.transform_keys! { "#{(key_prefix + [name]).join("/")}[]/#{
|
|
146
|
-
reference_mapping.transform_values! { "#{value_key_prefix}/#{
|
|
180
|
+
reference_mapping.transform_keys! { |k| "#{(key_prefix + [name]).join("/")}[]/#{k}" }
|
|
181
|
+
reference_mapping.transform_values! { |v| "#{value_key_prefix}/#{v}" }
|
|
147
182
|
|
|
148
183
|
mapping.merge!(reference_mapping)
|
|
184
|
+
elsif has_one_of?
|
|
185
|
+
one_of_mapping = {}
|
|
186
|
+
one_of_property.mapping(key_prefix: key_prefix + ["#{name}[]"], value_prefix: mapping_value_prefix(value_prefix: value_prefix, collection: true), mapping: one_of_mapping, version:)
|
|
187
|
+
mapping.merge!(one_of_mapping)
|
|
149
188
|
else
|
|
150
189
|
properties.values.each do |property|
|
|
151
190
|
property.mapping(key_prefix: key_prefix + ["#{name}[]"], value_prefix: mapping_value_prefix(value_prefix: value_prefix, collection: true), mapping:, version:)
|
|
@@ -36,11 +36,11 @@ module Verquest
|
|
|
36
36
|
|
|
37
37
|
# Create mapping for this const property
|
|
38
38
|
#
|
|
39
|
-
# @param key_prefix [Array<
|
|
39
|
+
# @param key_prefix [Array<String>] Prefix for the source key
|
|
40
40
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
41
41
|
# @param mapping [Hash] The mapping hash to be updated
|
|
42
42
|
# @param version [String, nil] The version to create mapping for
|
|
43
|
-
# @return [
|
|
43
|
+
# @return [void]
|
|
44
44
|
def mapping(key_prefix:, value_prefix:, mapping:, version: nil)
|
|
45
45
|
mapping[(key_prefix + [name]).join("/")] = mapping_value_key(value_prefix:)
|
|
46
46
|
end
|
|
@@ -48,11 +48,11 @@ module Verquest
|
|
|
48
48
|
|
|
49
49
|
# Create mapping for this enum property
|
|
50
50
|
#
|
|
51
|
-
# @param key_prefix [Array<
|
|
51
|
+
# @param key_prefix [Array<String>] Prefix for the source key
|
|
52
52
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
53
53
|
# @param mapping [Hash] The mapping hash to be updated
|
|
54
54
|
# @param version [String, nil] The version to create mapping for
|
|
55
|
-
# @return [
|
|
55
|
+
# @return [void]
|
|
56
56
|
def mapping(key_prefix:, value_prefix:, mapping:, version: nil)
|
|
57
57
|
mapping[(key_prefix + [name]).join("/")] = mapping_value_key(value_prefix:)
|
|
58
58
|
end
|
|
@@ -68,11 +68,11 @@ module Verquest
|
|
|
68
68
|
|
|
69
69
|
# Create mapping for this field property
|
|
70
70
|
#
|
|
71
|
-
# @param key_prefix [Array<
|
|
71
|
+
# @param key_prefix [Array<String>] Prefix for the source key
|
|
72
72
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
73
73
|
# @param mapping [Hash] The mapping hash to be updated
|
|
74
74
|
# @param version [String, nil] The version to create mapping for
|
|
75
|
-
# @return [
|
|
75
|
+
# @return [void]
|
|
76
76
|
def mapping(key_prefix:, value_prefix:, mapping:, version: nil)
|
|
77
77
|
mapping[(key_prefix + [name]).join("/")] = mapping_value_key(value_prefix:)
|
|
78
78
|
end
|
|
@@ -84,7 +84,7 @@ module Verquest
|
|
|
84
84
|
# @param value_prefix [Array<String>] Prefix for the target value
|
|
85
85
|
# @param mapping [Hash] The mapping hash to be updated
|
|
86
86
|
# @param version [String, nil] The version to create mapping for
|
|
87
|
-
# @return [
|
|
87
|
+
# @return [void]
|
|
88
88
|
def mapping(key_prefix:, value_prefix:, mapping:, version: nil)
|
|
89
89
|
properties.values.each do |property|
|
|
90
90
|
property.mapping(key_prefix: key_prefix + [name], value_prefix: mapping_value_prefix(value_prefix:), mapping:, version:)
|