verquest 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +8 -0
- data/CHANGELOG.md +2 -0
- data/README.md +416 -13
- data/lib/verquest/base/helper_class_methods.rb +37 -0
- data/lib/verquest/base/private_class_methods.rb +247 -0
- data/lib/verquest/base/public_class_methods.rb +108 -0
- data/lib/verquest/base.rb +38 -0
- data/lib/verquest/configuration.rb +73 -0
- data/lib/verquest/gem_version.rb +5 -0
- data/lib/verquest/properties/array.rb +63 -0
- data/lib/verquest/properties/base.rb +104 -0
- data/lib/verquest/properties/collection.rb +147 -0
- data/lib/verquest/properties/field.rb +65 -0
- data/lib/verquest/properties/object.rb +83 -0
- data/lib/verquest/properties/reference.rb +92 -0
- data/lib/verquest/properties.rb +47 -0
- data/lib/verquest/result.rb +75 -0
- data/lib/verquest/transformer.rb +179 -0
- data/lib/verquest/version.rb +208 -1
- data/lib/verquest/version_resolver.rb +42 -0
- data/lib/verquest/versions.rb +65 -0
- data/lib/verquest.rb +96 -3
- metadata +40 -6
data/lib/verquest/version.rb
CHANGED
@@ -1,5 +1,212 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Verquest
|
4
|
-
|
4
|
+
# Represents a specific version of an API request schema
|
5
|
+
#
|
6
|
+
# The Version class manages the properties, schema generation, and mapping
|
7
|
+
# for a specific version of an API request. It holds the collection of
|
8
|
+
# properties that define the request structure and handles
|
9
|
+
# transforming between different property naming conventions.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# version = Verquest::Version.new(name: "2023-01")
|
13
|
+
# version.add(Verquest::Properties::Field.new(name: :email, type: :string))
|
14
|
+
# version.prepare
|
15
|
+
#
|
16
|
+
# # Generate schema
|
17
|
+
# schema = version.schema
|
18
|
+
#
|
19
|
+
# # Get mapping
|
20
|
+
# mapping = version.mapping
|
21
|
+
class Version
|
22
|
+
# @!attribute [r] name
|
23
|
+
# @return [String] The name/identifier of the version (e.g., "2023-01")
|
24
|
+
#
|
25
|
+
# @!attribute [r] properties
|
26
|
+
# @return [Hash<Symbol, Verquest::Properties::Base>] The properties that define the version's schema
|
27
|
+
#
|
28
|
+
# @!attribute [r] schema
|
29
|
+
# @return [Hash] The generated JSON schema for this version
|
30
|
+
#
|
31
|
+
# @!attribute [r] validation_schema
|
32
|
+
# @return [Hash] The schema used for request validation
|
33
|
+
#
|
34
|
+
# @!attribute [r] mapping
|
35
|
+
# @return [Hash] The mapping from schema property paths to internal paths
|
36
|
+
#
|
37
|
+
# @!attribute [r] transformer
|
38
|
+
# @return [Verquest::Transformer] The transformer that applies the mapping
|
39
|
+
attr_reader :name, :properties, :schema, :validation_schema, :mapping, :transformer
|
40
|
+
|
41
|
+
# @!attribute [rw] schema_options
|
42
|
+
# @return [Hash] Additional JSON schema options for this version
|
43
|
+
#
|
44
|
+
# @!attribute [rw] description
|
45
|
+
# @return [String] Description of this version
|
46
|
+
attr_accessor :schema_options, :description
|
47
|
+
|
48
|
+
# Initialize a new Version instance
|
49
|
+
#
|
50
|
+
# @param name [String] The name/identifier of the version
|
51
|
+
# @return [Version] A new Version instance
|
52
|
+
def initialize(name:)
|
53
|
+
@name = name
|
54
|
+
@schema_options = {}
|
55
|
+
@properties = {}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add a property to this version
|
59
|
+
#
|
60
|
+
# @param property [Verquest::Properties::Base] The property to add
|
61
|
+
# @return [Verquest::Properties::Base] The added property
|
62
|
+
def add(property)
|
63
|
+
properties[property.name] = property
|
64
|
+
end
|
65
|
+
|
66
|
+
# Remove a property from this version by name
|
67
|
+
#
|
68
|
+
# @param property_name [Symbol, String] The name of the property to remove
|
69
|
+
# @return [Verquest::Properties::Base] The removed property
|
70
|
+
# @raise [PropertyNotFoundError] If the property doesn't exist
|
71
|
+
def remove(property_name)
|
72
|
+
properties.delete(property_name) || raise(PropertyNotFoundError.new("Property '#{property_name}' is not defined on '#{name}"))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Check if this version has a property with the given name
|
76
|
+
#
|
77
|
+
# @param property_name [Symbol, String] The name of the property to check
|
78
|
+
# @return [Boolean] true if the property exists, false otherwise
|
79
|
+
def has?(property_name)
|
80
|
+
properties.key?(property_name)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Copy properties from another version
|
84
|
+
#
|
85
|
+
# @param version [Verquest::Version] The version to copy properties from
|
86
|
+
# @param exclude_properties [Array<Symbol>] Names of properties to not copy
|
87
|
+
# @return [void]
|
88
|
+
# @raise [ArgumentError] If version is not a Verquest::Version instance
|
89
|
+
def copy_from(version, exclude_properties: [])
|
90
|
+
raise ArgumentError, "Expected a Verquest::Version instance" unless version.is_a?(Version)
|
91
|
+
|
92
|
+
version.properties.values.each do |property|
|
93
|
+
next if exclude_properties.include?(property.name)
|
94
|
+
|
95
|
+
add(property)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Prepare this version by generating schema and creating transformer
|
100
|
+
#
|
101
|
+
# @return [void]
|
102
|
+
def prepare
|
103
|
+
return if frozen?
|
104
|
+
|
105
|
+
prepare_schema
|
106
|
+
prepare_validation_schema
|
107
|
+
prepare_mapping
|
108
|
+
@transformer = Transformer.new(mapping: mapping)
|
109
|
+
|
110
|
+
freeze
|
111
|
+
end
|
112
|
+
|
113
|
+
# Validate the schema against the metaschema
|
114
|
+
#
|
115
|
+
# @return [Boolean] true if the schema is valid, false otherwise
|
116
|
+
def validate_schema
|
117
|
+
schema_name = Verquest.configuration.json_schema_version
|
118
|
+
|
119
|
+
metaschema = JSON::Validator.validator_for_name(schema_name).metaschema
|
120
|
+
JSON::Validator.validate(metaschema, validation_schema)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Validate request parameters against the version's validation schema
|
124
|
+
#
|
125
|
+
# @param params [Hash] The request parameters to validate
|
126
|
+
# @param component_reference [String] A reference string for components in the schema
|
127
|
+
# @param remove_extra_root_keys [Boolean] Whether to remove extra keys not in the schema
|
128
|
+
# @return [Array<Hash>] An array of validation error details, or empty if valid
|
129
|
+
def validate_params(params:, component_reference:, remove_extra_root_keys:)
|
130
|
+
schema_name = Verquest.configuration.json_schema_version
|
131
|
+
|
132
|
+
result = JSON::Validator.fully_validate(validation_schema, params, version: schema_name, errors_as_objects: true)
|
133
|
+
return result if result.empty?
|
134
|
+
|
135
|
+
result.map do |error|
|
136
|
+
schema = error.delete(:schema)
|
137
|
+
error[:message].gsub!(schema.to_s, component_reference)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Get the mapping for a specific property
|
142
|
+
#
|
143
|
+
# @param property [Symbol, String] The property name to get the mapping for
|
144
|
+
# @return [Hash] The mapping for the property
|
145
|
+
# @raise [PropertyNotFoundError] If the property doesn't exist
|
146
|
+
def mapping_for(property)
|
147
|
+
raise PropertyNotFoundError.new("Property '#{property}' is not defined on '#{name}'") unless has?(property)
|
148
|
+
|
149
|
+
{}.tap do |mapping|
|
150
|
+
properties[property].mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Map request parameters to internal representation using the transformer
|
155
|
+
#
|
156
|
+
# @param params [Hash] The request parameters to map
|
157
|
+
# @return [Hash] The mapped parameters
|
158
|
+
def map_params(params)
|
159
|
+
transformer.call(params)
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
# Generates the JSON schema for this version
|
165
|
+
#
|
166
|
+
# Creates a schema object with type, description, required properties,
|
167
|
+
# and property definitions based on the properties in this version.
|
168
|
+
# The schema is frozen to prevent modification after preparation.
|
169
|
+
#
|
170
|
+
# @return [Hash] The frozen schema hash
|
171
|
+
def prepare_schema
|
172
|
+
@schema = {
|
173
|
+
type: :object,
|
174
|
+
description: description,
|
175
|
+
required: properties.values.select(&:required).map(&:name),
|
176
|
+
properties: properties.transform_values { |property| property.to_schema[property.name] }
|
177
|
+
}.merge(schema_options).freeze
|
178
|
+
end
|
179
|
+
|
180
|
+
# Generates the validation schema for this version
|
181
|
+
#
|
182
|
+
# Similar to prepare_schema but specifically for validation purposes.
|
183
|
+
# The validation schema will include all referenced components and properties.
|
184
|
+
#
|
185
|
+
# @return [Hash] The frozen validation schema hash
|
186
|
+
def prepare_validation_schema
|
187
|
+
@validation_schema = {
|
188
|
+
type: :object,
|
189
|
+
description: description,
|
190
|
+
required: properties.values.select(&:required).map(&:name),
|
191
|
+
properties: properties.transform_values { |property| property.to_validation_schema(version: name)[property.name] }
|
192
|
+
}.merge(schema_options).freeze
|
193
|
+
end
|
194
|
+
|
195
|
+
# Prepares the parameter mapping for this version
|
196
|
+
#
|
197
|
+
# Collects mappings from all properties in this version and checks for
|
198
|
+
# duplicate mappings, which would cause conflicts during transformation.
|
199
|
+
#
|
200
|
+
# @return [Hash] The mapping from schema property paths to internal paths
|
201
|
+
# @raise [MappingError] If duplicate mappings are detected
|
202
|
+
def prepare_mapping
|
203
|
+
@mapping = properties.values.each_with_object({}) do |property, mapping|
|
204
|
+
property.mapping(key_prefix: [], value_prefix: [], mapping: mapping, version: name)
|
205
|
+
end
|
206
|
+
|
207
|
+
if (duplicates = mapping.keys.select { |k| mapping.values.count(k) > 1 }).any?
|
208
|
+
raise MappingError.new("Mapping must be unique. Found duplicates in version '#{name}': #{duplicates.join(", ")}")
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
5
212
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Verquest
|
4
|
+
# Resolves requested version identifiers to actual version objects
|
5
|
+
#
|
6
|
+
# The VersionResolver handles version resolution logic, finding the appropriate
|
7
|
+
# version to use based on a requested version identifier. It implements a "downgrading"
|
8
|
+
# strategy - when an exact version match isn't found, it returns the closest earlier version.
|
9
|
+
#
|
10
|
+
# @example Resolving a version
|
11
|
+
# versions = ["2025-01", "2025-06", "2026-01"]
|
12
|
+
#
|
13
|
+
# # Exact match
|
14
|
+
# Verquest::VersionResolver.call("2025-06", versions) # => "2025-06"
|
15
|
+
#
|
16
|
+
# # Between versions - returns previous version
|
17
|
+
# Verquest::VersionResolver.call("2025-04", versions) # => "2025-01"
|
18
|
+
#
|
19
|
+
# # After latest version - returns latest
|
20
|
+
# Verquest::VersionResolver.call("2026-06", versions) # => "2026-01"
|
21
|
+
class VersionResolver
|
22
|
+
# Resolves a requested version to the appropriate available version
|
23
|
+
#
|
24
|
+
# This method implements the version resolution strategy:
|
25
|
+
# - If an exact match is found, that version is returned
|
26
|
+
# - If the requested version is between two available versions, the earlier one is returned
|
27
|
+
# - If the requested version is after all available versions, the latest version is returned
|
28
|
+
#
|
29
|
+
# @param requested_version [String] The version identifier requested
|
30
|
+
# @param versions [Array<String>] List of available version identifiers, sorted by age (oldest first)
|
31
|
+
# @return [String, nil] The resolved version, or nil if no versions available
|
32
|
+
def self.call(requested_version, versions)
|
33
|
+
versions.each_with_index do |version, index|
|
34
|
+
return version if version == requested_version
|
35
|
+
|
36
|
+
if requested_version > version && ((versions[index + 1] && requested_version < versions[index + 1]) || !versions[index + 1])
|
37
|
+
return version
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Verquest
|
4
|
+
# Container for managing multiple API versions
|
5
|
+
#
|
6
|
+
# The Versions class stores and provides access to all available versions of an
|
7
|
+
# API request schema. It handles adding new versions and resolving version identifiers
|
8
|
+
# to specific Version objects based on the configured version resolution strategy.
|
9
|
+
#
|
10
|
+
# @example Adding and resolving versions
|
11
|
+
# versions = Verquest::Versions.new
|
12
|
+
#
|
13
|
+
# # Add versions
|
14
|
+
# versions.add(Verquest::Version.new(name: "2022-01"))
|
15
|
+
# versions.add(Verquest::Version.new(name: "2023-01"))
|
16
|
+
#
|
17
|
+
# # Resolve a version
|
18
|
+
# version = versions.resolve("2022-06") # Returns "2022-01" version based on resolver
|
19
|
+
class Versions
|
20
|
+
# @!attribute [rw] description
|
21
|
+
# @return [String] Default description for versions that don't specify one
|
22
|
+
#
|
23
|
+
# @!attribute [rw] schema_options
|
24
|
+
# @return [Hash] Default schema options for versions that don't specify any
|
25
|
+
attr_accessor :description, :schema_options
|
26
|
+
|
27
|
+
# Initialize a new Versions container
|
28
|
+
#
|
29
|
+
# @return [Versions] A new Versions instance
|
30
|
+
def initialize
|
31
|
+
@versions = {}
|
32
|
+
@schema_options = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
# Add a version to the container
|
36
|
+
#
|
37
|
+
# @param version [Verquest::Version] The version to add
|
38
|
+
# @return [Verquest::Version] The added version
|
39
|
+
# @raise [ArgumentError] If the provided object is not a Version instance
|
40
|
+
def add(version)
|
41
|
+
raise ArgumentError, "Expected a Verquest::Version instance" unless version.is_a?(Verquest::Version)
|
42
|
+
|
43
|
+
versions[version.name] = version
|
44
|
+
end
|
45
|
+
|
46
|
+
# Resolve a version identifier to a specific Version object
|
47
|
+
#
|
48
|
+
# Uses the configured version resolver to determine which version to use
|
49
|
+
# based on the requested version identifier.
|
50
|
+
#
|
51
|
+
# @param version_name [String] The version identifier to resolve
|
52
|
+
# @return [Verquest::Version] The resolved Version object
|
53
|
+
def resolve(version_name)
|
54
|
+
resolved_version_name = Verquest.configuration.version_resolver.call(version_name, versions.keys.sort)
|
55
|
+
|
56
|
+
versions[resolved_version_name] || raise(Verquest::VersionNotFoundError, "Version '#{version_name}' not found")
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# @!attribute [r] versions
|
62
|
+
# @return [Hash<String, Verquest::Version>] The versions stored in this container
|
63
|
+
attr_reader :versions
|
64
|
+
end
|
65
|
+
end
|
data/lib/verquest.rb
CHANGED
@@ -1,10 +1,103 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "zeitwerk"
|
4
|
-
|
4
|
+
require "json-schema"
|
5
|
+
|
6
|
+
loader = Zeitwerk::Loader.new
|
7
|
+
loader.tag = File.basename(__FILE__, ".rb")
|
8
|
+
loader.push_dir(File.dirname(__FILE__))
|
5
9
|
loader.setup
|
6
10
|
|
11
|
+
# Verquest is a Ruby gem for versioning API requests
|
12
|
+
#
|
13
|
+
# Verquest allows you to define and manage versioned API request schemas,
|
14
|
+
# handle parameter mapping between different versions, validate incoming
|
15
|
+
# parameters against schemas, and generate documentation.
|
16
|
+
#
|
17
|
+
# @example Basic usage
|
18
|
+
# class UserCreateRequest < Verquest::Base
|
19
|
+
# description "User Create Request"
|
20
|
+
# schema_options additional_properties: false
|
21
|
+
#
|
22
|
+
# version "2025-06" do
|
23
|
+
# field :email, type: :string, required: true, format: "email"
|
24
|
+
# field :name, type: :string
|
25
|
+
#
|
26
|
+
# object :address do
|
27
|
+
# field :street, type: :string, map: "/address_street"
|
28
|
+
# field :city, type: :string, required: true, map: "/address_city"
|
29
|
+
# field :zip_code, type: :string, map: "/address_zip_code"
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# version "2025-08", exclude_properties: %i[name] do
|
34
|
+
# field :name, type: :string, required: true
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # Map and validate parameters for a specific version
|
39
|
+
# result = UserCreateRequest.map(params, version: "2025-07", validate: true)
|
40
|
+
#
|
41
|
+
# if result.success?
|
42
|
+
# process_user(result.value)
|
43
|
+
# else
|
44
|
+
# handle_errors(result.errors)
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @see Verquest::Base Base class for creating versioned request schemas
|
48
|
+
# @see Verquest::Configuration Configuration options for Verquest
|
7
49
|
module Verquest
|
8
|
-
class
|
9
|
-
#
|
50
|
+
# Base error class for all Verquest-related errors
|
51
|
+
# @api public
|
52
|
+
Error = Class.new(StandardError)
|
53
|
+
|
54
|
+
# Error raised when a requested version cannot be found
|
55
|
+
# @api public
|
56
|
+
VersionNotFoundError = Class.new(Verquest::Error)
|
57
|
+
|
58
|
+
# Error raised when a requested property cannot be found in a version
|
59
|
+
# @api public
|
60
|
+
PropertyNotFoundError = Class.new(Verquest::Error)
|
61
|
+
|
62
|
+
# Error raised when there are issues with property mappings
|
63
|
+
# @api public
|
64
|
+
MappingError = Class.new(Verquest::Error)
|
65
|
+
|
66
|
+
# Error raised when parameters do not match the expected schema
|
67
|
+
# @api public
|
68
|
+
InvalidParamsError = Class.new(Verquest::Error) do
|
69
|
+
attr_reader :errors
|
70
|
+
|
71
|
+
# @param message [String] error message
|
72
|
+
# @param errors [Array] validation errors
|
73
|
+
def initialize(message, errors:)
|
74
|
+
super(message)
|
75
|
+
@errors = errors
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
# Returns the global configuration for Verquest
|
81
|
+
#
|
82
|
+
# @return [Verquest::Configuration] The configuration instance
|
83
|
+
# @see Verquest::Configuration
|
84
|
+
def configuration
|
85
|
+
@configuration ||= Configuration.new
|
86
|
+
end
|
87
|
+
|
88
|
+
# Configure Verquest with the given block
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# Verquest.configure do |config|
|
92
|
+
# config.validate_params = true
|
93
|
+
# config.current_version = -> { "2023-06" }
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# @yield [configuration] The configuration instance
|
97
|
+
# @yieldparam configuration [Verquest::Configuration] The configuration to modify
|
98
|
+
# @return [void]
|
99
|
+
def configure
|
100
|
+
yield(configuration)
|
101
|
+
end
|
102
|
+
end
|
10
103
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: verquest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Petr Hlavicka
|
@@ -23,23 +23,56 @@ dependencies:
|
|
23
23
|
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '2.7'
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: json-schema
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5.0'
|
40
|
+
description: Verquest helps you version API requests, simplifying the management of
|
41
|
+
changes, handling the mapping for internal versus external names and structures,
|
42
|
+
validating parameters, and exporting your requests to JSON Schema components for
|
43
|
+
OpenAPI.
|
29
44
|
email:
|
30
|
-
- petr
|
45
|
+
- yes@petr.codes
|
31
46
|
executables: []
|
32
47
|
extensions: []
|
33
48
|
extra_rdoc_files: []
|
34
49
|
files:
|
35
50
|
- ".rubocop.yml"
|
51
|
+
- ".yardopts"
|
36
52
|
- CHANGELOG.md
|
37
53
|
- CODE_OF_CONDUCT.md
|
38
54
|
- LICENSE.txt
|
39
55
|
- README.md
|
40
56
|
- Rakefile
|
41
57
|
- lib/verquest.rb
|
58
|
+
- lib/verquest/base.rb
|
59
|
+
- lib/verquest/base/helper_class_methods.rb
|
60
|
+
- lib/verquest/base/private_class_methods.rb
|
61
|
+
- lib/verquest/base/public_class_methods.rb
|
62
|
+
- lib/verquest/configuration.rb
|
63
|
+
- lib/verquest/gem_version.rb
|
64
|
+
- lib/verquest/properties.rb
|
65
|
+
- lib/verquest/properties/array.rb
|
66
|
+
- lib/verquest/properties/base.rb
|
67
|
+
- lib/verquest/properties/collection.rb
|
68
|
+
- lib/verquest/properties/field.rb
|
69
|
+
- lib/verquest/properties/object.rb
|
70
|
+
- lib/verquest/properties/reference.rb
|
71
|
+
- lib/verquest/result.rb
|
72
|
+
- lib/verquest/transformer.rb
|
42
73
|
- lib/verquest/version.rb
|
74
|
+
- lib/verquest/version_resolver.rb
|
75
|
+
- lib/verquest/versions.rb
|
43
76
|
homepage: https://github.com/CiTroNaK/verquest
|
44
77
|
licenses:
|
45
78
|
- MIT
|
@@ -63,5 +96,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
96
|
requirements: []
|
64
97
|
rubygems_version: 3.6.7
|
65
98
|
specification_version: 4
|
66
|
-
summary:
|
99
|
+
summary: Verquest is a Ruby gem that offers an elegant solution for versioning API
|
100
|
+
requests
|
67
101
|
test_files: []
|