dry_validation_openapi 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 29d8e1b449631809fa220bb41125221b44443097ae83533a7b71c97cc88d6e7e
4
+ data.tar.gz: d070b609ff5ae658efe41c6ede707c4520473195819dd52b918b6e39779a5297
5
+ SHA512:
6
+ metadata.gz: a58f1f2e0ad933889dbd367d23a148ba9dc1ed537e9d999ba6cfeccefc01b9e59e28b66d6c7f85b7392bd4357f8d07382785e712afda8267bfc1c7b7a539f776
7
+ data.tar.gz: 2fcb73cc379258c609bec33e59133cf398161930677ec1b46da2626188288acf4d9b748c5d295cf221c464b7d0ef59d89d2e2d46ee06431c0c96f35cc320e71d
data/CHANGELOG.md ADDED
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2025-12-11
9
+
10
+ ### Added
11
+ - Initial release
12
+ - Support for required and optional fields
13
+ - Support for basic types: string, integer, float, decimal, boolean
14
+ - Type format specifications (int32, double, float, date, date-time)
15
+ - Support for array types with item schemas
16
+ - Support for nested objects/hashes with properties
17
+ - Support for arrays of objects with nested schemas
18
+ - Support for multiple nested objects at the same level
19
+ - Support for both `.value()` and `.filled()` predicates
20
+ - `Convertable` module for easy integration with dry-validation contracts
21
+ - Static parsing using Ruby's built-in Ripper parser
22
+ - Zero runtime dependencies (besides Ruby standard library)
23
+
24
+ ### Features
25
+ - `extend DryValidationOpenapi::Convertable` to add `.open_api_schema` method to contracts
26
+ - Automatic parent tracking for nested schemas
27
+ - OpenAPI 3.0 compatible schema generation
28
+ - Works with rswag and other OpenAPI tools
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 [Your Name]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # DryValidationOpenapi
2
+
3
+ Automatically generate OpenAPI 3.0 schemas from [dry-validation](https://dry-rb.org/gems/dry-validation/) contracts for use with [rswag](https://github.com/rswag/rswag) and other OpenAPI tools.
4
+
5
+ Instead of manually writing OpenAPI schemas for your API documentation, this gem extracts type information directly from your dry-validation contract definitions using static parsing.
6
+
7
+ ## Features
8
+
9
+ - 🎯 **Zero runtime overhead** - Uses static parsing, no contract instantiation needed
10
+ - 🔄 **Automatic conversion** - Converts dry-validation types to OpenAPI types with formats
11
+ - 🪆 **Nested schemas** - Handles nested objects and arrays of objects
12
+ - 📝 **Simple API** - Just `extend` your contract and call `.open_api_schema`
13
+ - ✅ **Type formats** - Includes OpenAPI format specifications (int32, double, date-time, etc.)
14
+
15
+ ## Supported Features
16
+
17
+ ### ✅ Currently Supported
18
+
19
+ - [x] Required and optional fields
20
+ - [x] Basic types: string, integer, float, decimal, boolean
21
+ - [x] Type formats: int32, double, float, date, date-time
22
+ - [x] Array types with item schemas
23
+ - [x] Nested objects/hashes with properties
24
+ - [x] Arrays of objects with nested schemas
25
+ - [x] Multiple nested objects at the same level
26
+ - [x] `.value()` and `.filled()` predicates
27
+
28
+ ### 📋 Not Yet Implemented
29
+
30
+ - [ ] Custom type formats (email, uuid, etc.)
31
+ - [ ] Descriptions and examples
32
+ - [ ] Min/max constraints
33
+ - [ ] Enums
34
+ - [ ] Custom rules/validations
35
+ - [ ] Pattern validations
36
+ - [ ] Maybe/nil handling
37
+
38
+ ## Installation
39
+
40
+ Add this line to your application's Gemfile:
41
+
42
+ ```ruby
43
+ gem 'dry_validation_openapi'
44
+ ```
45
+
46
+ And then execute:
47
+
48
+ ```bash
49
+ bundle install
50
+ ```
51
+
52
+ Or install it yourself as:
53
+
54
+ ```bash
55
+ gem install dry_validation_openapi
56
+ ```
57
+
58
+ ## Usage
59
+
60
+ ### Basic Usage
61
+
62
+ ```ruby
63
+ require 'dry_validation_openapi'
64
+
65
+ class CreateUserContract < Dry::Validation::Contract
66
+ extend DryValidationOpenapi::Convertable
67
+
68
+ params do
69
+ required(:email).value(:string)
70
+ required(:age).value(:integer)
71
+ optional(:name).value(:string)
72
+ end
73
+ end
74
+
75
+ # Generate OpenAPI schema
76
+ schema = CreateUserContract.open_api_schema
77
+ # => {
78
+ # type: :object,
79
+ # properties: {
80
+ # email: { type: :string },
81
+ # age: { type: :integer, format: 'int32' },
82
+ # name: { type: :string }
83
+ # },
84
+ # required: ['email', 'age']
85
+ # }
86
+ ```
87
+
88
+ ### With rswag
89
+
90
+ Use in your rswag request specs:
91
+
92
+ ```ruby
93
+ # spec/requests/users_spec.rb
94
+ require 'swagger_helper'
95
+
96
+ RSpec.describe 'Users API' do
97
+ path '/users' do
98
+ post 'Creates a user' do
99
+ tags 'Users'
100
+ consumes 'application/json'
101
+
102
+ parameter name: :body,
103
+ in: :body,
104
+ required: true,
105
+ schema: CreateUserContract.open_api_schema
106
+
107
+ response '201', 'user created' do
108
+ let(:body) { { email: 'user@example.com', age: 25 } }
109
+ run_test!
110
+ end
111
+ end
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Nested Objects
117
+
118
+ ```ruby
119
+ class CreateOrderContract < Dry::Validation::Contract
120
+ extend DryValidationOpenapi::Convertable
121
+
122
+ params do
123
+ required(:order_id).value(:string)
124
+ required(:customer).hash do
125
+ required(:name).value(:string)
126
+ required(:email).value(:string)
127
+ end
128
+ end
129
+ end
130
+
131
+ CreateOrderContract.open_api_schema
132
+ # => {
133
+ # type: :object,
134
+ # properties: {
135
+ # order_id: { type: :string },
136
+ # customer: {
137
+ # type: :object,
138
+ # properties: {
139
+ # name: { type: :string },
140
+ # email: { type: :string }
141
+ # },
142
+ # required: ['name', 'email']
143
+ # }
144
+ # },
145
+ # required: ['order_id', 'customer']
146
+ # }
147
+ ```
148
+
149
+ ### Arrays of Objects
150
+
151
+ ```ruby
152
+ class CreateInvoiceContract < Dry::Validation::Contract
153
+ extend DryValidationOpenapi::Convertable
154
+
155
+ params do
156
+ required(:issue_date).value(:time)
157
+ required(:line_items).array(:hash) do
158
+ required(:description).filled(:string)
159
+ required(:amount).filled(:decimal)
160
+ end
161
+ end
162
+ end
163
+
164
+ CreateInvoiceContract.open_api_schema
165
+ # => {
166
+ # type: :object,
167
+ # properties: {
168
+ # issue_date: { type: :string, format: 'date-time' },
169
+ # line_items: {
170
+ # type: :array,
171
+ # items: {
172
+ # type: :object,
173
+ # properties: {
174
+ # description: { type: :string },
175
+ # amount: { type: :number, format: 'double' }
176
+ # },
177
+ # required: ['description', 'amount']
178
+ # }
179
+ # }
180
+ # },
181
+ # required: ['issue_date', 'line_items']
182
+ # }
183
+ ```
184
+
185
+ ## Type Mappings
186
+
187
+ | dry-validation type | OpenAPI type | OpenAPI format |
188
+ |---------------------|--------------|----------------|
189
+ | `:string` | `string` | - |
190
+ | `:integer`, `:int` | `integer` | `int32` |
191
+ | `:float` | `number` | `float` |
192
+ | `:decimal`, `:number` | `number` | `double` |
193
+ | `:bool`, `:boolean` | `boolean` | - |
194
+ | `:date` | `string` | `date` |
195
+ | `:time`, `:date_time` | `string` | `date-time` |
196
+ | `:hash` | `object` | - |
197
+ | `:array` | `array` | - |
198
+
199
+ ## How It Works
200
+
201
+ This gem uses **static parsing** rather than runtime introspection:
202
+
203
+ 1. **Reads the contract file** as plain text using the contract's source location
204
+ 2. **Parses to AST** using Ruby's built-in Ripper parser
205
+ 3. **Walks the AST** to find the `params do...end` block
206
+ 4. **Extracts field definitions** (required/optional, names, types, nesting)
207
+ 5. **Converts to OpenAPI schema** format
208
+
209
+ This approach is:
210
+ - ✅ Fast and lightweight (no contract instantiation)
211
+ - ✅ Simple to understand (just parsing Ruby code)
212
+ - ✅ Works without dry-validation loaded
213
+ - ⚠️ Cannot handle dynamically-generated contracts (rare in practice)
214
+
215
+ ## Development
216
+
217
+ After checking out the repo, run:
218
+
219
+ ```bash
220
+ bundle install
221
+ ```
222
+
223
+ Run the tests:
224
+
225
+ ```bash
226
+ bundle exec rspec
227
+ ```
228
+
229
+ Build the gem:
230
+
231
+ ```bash
232
+ gem build dry_validation_openapi.gemspec
233
+ ```
234
+
235
+ ## Contributing
236
+
237
+ Bug reports and pull requests are welcome on GitHub at https://github.com/troptropcontent/dry_validation_openapi.
238
+
239
+ ## License
240
+
241
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
242
+
243
+ ## Credits
244
+
245
+ Created to solve the problem of maintaining duplicate schema definitions in dry-validation contracts and OpenAPI documentation.
@@ -0,0 +1,200 @@
1
+ require 'ripper'
2
+
3
+ module DryValidationOpenapi
4
+ class ContractParser
5
+ def self.parse_file(file_path)
6
+ source = File.read(file_path)
7
+ new(source).parse
8
+ end
9
+
10
+ def initialize(source)
11
+ @source = source
12
+ @schema_definitions = []
13
+ end
14
+
15
+ def parse
16
+ sexp = Ripper.sexp(@source)
17
+ find_params_block(sexp)
18
+ @schema_definitions
19
+ end
20
+
21
+ private
22
+
23
+ def find_params_block(node)
24
+ return unless node.is_a?(Array)
25
+
26
+ # Look for method_add_block with params
27
+ if node[0] == :method_add_block
28
+ method_call = node[1]
29
+ if method_call.is_a?(Array) && is_params_call?(method_call)
30
+ # Found the params block
31
+ do_block = node[2]
32
+ if do_block && do_block[0] == :do_block
33
+ extract_params_body(do_block)
34
+ end
35
+ return
36
+ end
37
+ end
38
+
39
+ # Recursively search
40
+ node.each { |child| find_params_block(child) }
41
+ end
42
+
43
+ def is_params_call?(node)
44
+ return false unless node.is_a?(Array)
45
+
46
+ case node[0]
47
+ when :method_add_arg
48
+ fcall = node[1]
49
+ return fcall.is_a?(Array) && fcall[0] == :fcall && fcall[1].is_a?(Array) && fcall[1][1] == 'params'
50
+ when :fcall
51
+ return node[1].is_a?(Array) && node[1][1] == 'params'
52
+ end
53
+
54
+ false
55
+ end
56
+
57
+ def extract_params_body(do_block)
58
+ # do_block structure: [:do_block, params, [:bodystmt, statements, ...]]
59
+ body = do_block[2]
60
+ return unless body && body[0] == :bodystmt
61
+
62
+ statements = body[1]
63
+ extract_statements(statements, depth: 0, parent: nil)
64
+ end
65
+
66
+ def extract_statements(statements, depth:, parent:)
67
+ return unless statements.is_a?(Array)
68
+
69
+ statements.each do |stmt|
70
+ case stmt[0]
71
+ when :method_add_arg, :call
72
+ # Simple field definition like required(:email).value(:string)
73
+ # or optional(:metadata).hash
74
+ field_info = parse_method_chain(stmt, depth: depth, parent: parent)
75
+ @schema_definitions << field_info if field_info
76
+ when :method_add_block
77
+ # Field with nested block like required(:settings).hash do...end
78
+ field_info = parse_method_chain(stmt[1], depth: depth, parent: parent, has_block: true)
79
+ if field_info
80
+ @schema_definitions << field_info
81
+
82
+ # Extract nested fields with this field as their parent
83
+ nested_block = stmt[2]
84
+ if nested_block && nested_block[0] == :do_block
85
+ nested_body = nested_block[2]
86
+ if nested_body && nested_body[0] == :bodystmt
87
+ extract_statements(nested_body[1], depth: depth + 1, parent: field_info[:name])
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ def parse_method_chain(node, depth:, parent:, has_block: false)
96
+ # Extract the base method (required/optional)
97
+ base_method = find_base_method(node)
98
+ return nil unless base_method && ['required', 'optional'].include?(base_method)
99
+
100
+ # Extract field name (symbol argument to required/optional)
101
+ field_name = find_field_name(node)
102
+ return nil unless field_name
103
+
104
+ # Extract type information (.value, .array, .hash, etc.)
105
+ type_info = find_type_info(node, has_block: has_block)
106
+
107
+ {
108
+ required: base_method == 'required',
109
+ name: field_name,
110
+ type: type_info[:type],
111
+ sub_type: type_info[:sub_type],
112
+ has_nested: type_info[:has_nested],
113
+ depth: depth,
114
+ parent: parent
115
+ }
116
+ end
117
+
118
+ def find_base_method(node)
119
+ return nil unless node.is_a?(Array)
120
+
121
+ case node[0]
122
+ when :method_add_arg, :call
123
+ return find_base_method(node[1])
124
+ when :fcall
125
+ ident = node[1]
126
+ return ident[1] if ident && ident[0] == :@ident
127
+ end
128
+
129
+ nil
130
+ end
131
+
132
+ def find_field_name(node)
133
+ symbols = find_all_symbols(node)
134
+ symbols.first # The first symbol is the field name
135
+ end
136
+
137
+ def find_all_symbols(node, symbols = [])
138
+ return symbols unless node.is_a?(Array)
139
+
140
+ if node[0] == :symbol_literal
141
+ symbol_node = node[1]
142
+ if symbol_node && symbol_node[0] == :symbol
143
+ ident = symbol_node[1]
144
+ if ident && ident[0] == :@ident
145
+ symbols << ident[1]
146
+ end
147
+ end
148
+ end
149
+
150
+ node.each { |child| find_all_symbols(child, symbols) }
151
+ symbols
152
+ end
153
+
154
+ def find_type_info(node, has_block: false)
155
+ # Look for method calls like .value(:string), .filled(:string), .array(:string), .hash
156
+ type_method = find_type_method_name(node)
157
+
158
+ case type_method
159
+ when 'value', 'filled'
160
+ # Both .value() and .filled() take the same type argument
161
+ # .filled() additionally ensures the value is not nil/empty
162
+ symbols = find_all_symbols(node)
163
+ type_value = symbols[1] # First symbol is field name, second is type
164
+ { type: type_value, sub_type: nil, has_nested: false }
165
+ when 'array'
166
+ symbols = find_all_symbols(node)
167
+ sub_type = symbols[1] # Type of array items
168
+ { type: 'array', sub_type: sub_type, has_nested: has_block }
169
+ when 'hash'
170
+ { type: 'hash', sub_type: nil, has_nested: has_block }
171
+ else
172
+ # No type specified, default to string
173
+ { type: nil, sub_type: nil, has_nested: false }
174
+ end
175
+ end
176
+
177
+ def find_type_method_name(node)
178
+ return nil unless node.is_a?(Array)
179
+
180
+ case node[0]
181
+ when :call
182
+ # [:call, receiver, period, method_name]
183
+ method_name = node[3]
184
+ if method_name && method_name[0] == :@ident
185
+ return method_name[1]
186
+ end
187
+ # Continue searching in receiver
188
+ find_type_method_name(node[1])
189
+ when :method_add_arg
190
+ find_type_method_name(node[1])
191
+ else
192
+ node.each do |child|
193
+ result = find_type_method_name(child)
194
+ return result if result
195
+ end
196
+ nil
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,41 @@
1
+ module DryValidationOpenapi
2
+ # Module to extend dry-validation contracts with OpenAPI schema generation
3
+ #
4
+ # @example
5
+ # class CreateUserContract < Dry::Validation::Contract
6
+ # extend DryValidationOpenapi::Convertable
7
+ #
8
+ # params do
9
+ # required(:email).value(:string)
10
+ # required(:age).value(:integer)
11
+ # end
12
+ # end
13
+ #
14
+ # # In your rswag spec
15
+ # parameter name: :body, in: :body, schema: CreateUserContract.open_api_schema
16
+ #
17
+ module Convertable
18
+ # Returns the file path where this contract class is defined
19
+ #
20
+ # @return [String] the absolute path to the contract file
21
+ def location
22
+ @location ||= Object.const_source_location(name)[0]
23
+ end
24
+
25
+ # Generates an OpenAPI schema from this contract's params block
26
+ #
27
+ # @return [Hash] OpenAPI schema hash with type, properties, and required fields
28
+ def open_api_schema
29
+ @open_api_schema ||= SchemaBuilder.build(location)
30
+ end
31
+
32
+ # Clears the cached schema, forcing regeneration on next access
33
+ # Useful during development or when contract definition changes
34
+ #
35
+ # @return [nil]
36
+ def clear_schema_cache!
37
+ @open_api_schema = nil
38
+ @location = nil
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,125 @@
1
+ require_relative 'contract_parser'
2
+
3
+ module DryValidationOpenapi
4
+ class SchemaBuilder
5
+ # Maps dry-validation types to OpenAPI type (and optionally format)
6
+ # See: https://swagger.io/specification/#data-types
7
+ TYPE_MAPPING = {
8
+ 'string' => :string,
9
+ 'integer' => { type: :integer, format: 'int32' },
10
+ 'int' => { type: :integer, format: 'int32' },
11
+ 'float' => { type: :number, format: 'float' },
12
+ 'decimal' => { type: :number, format: 'double' },
13
+ 'number' => { type: :number, format: 'double' },
14
+ 'bool' => :boolean,
15
+ 'boolean' => :boolean,
16
+ 'date' => { type: :string, format: 'date' },
17
+ 'time' => { type: :string, format: 'date-time' },
18
+ 'date_time' => { type: :string, format: 'date-time' },
19
+ 'array' => :array,
20
+ 'hash' => :object
21
+ }.freeze
22
+
23
+ def self.build(contract_file_path)
24
+ new(contract_file_path).build
25
+ end
26
+
27
+ def initialize(contract_file_path)
28
+ @contract_file_path = contract_file_path
29
+ @definitions = []
30
+ end
31
+
32
+ def build
33
+ @definitions = ContractParser.parse_file(@contract_file_path)
34
+ build_schema(@definitions)
35
+ end
36
+
37
+ private
38
+
39
+ def build_schema(definitions, depth = 0, parent = nil)
40
+ schema = {
41
+ type: :object,
42
+ properties: {},
43
+ required: []
44
+ }
45
+
46
+ # Group definitions by depth and parent to handle nesting
47
+ current_level = definitions.select { |d| d[:depth] == depth && d[:parent] == parent }
48
+
49
+ current_level.each do |field|
50
+ property_schema = build_property_schema(field, definitions, depth)
51
+ schema[:properties][field[:name].to_sym] = property_schema
52
+ schema[:required] << field[:name] if field[:required]
53
+ end
54
+
55
+ # Clean up empty required array
56
+ schema.delete(:required) if schema[:required].empty?
57
+
58
+ schema
59
+ end
60
+
61
+ def build_property_schema(field, all_definitions, current_depth)
62
+ case field[:type]
63
+ when 'array'
64
+ build_array_schema(field, all_definitions, current_depth)
65
+ when 'hash'
66
+ build_hash_schema(field, all_definitions, current_depth)
67
+ else
68
+ build_simple_schema(field)
69
+ end
70
+ end
71
+
72
+ def build_simple_schema(field)
73
+ type_info = TYPE_MAPPING[field[:type]] || :string
74
+
75
+ # type_info can be either a symbol (:string) or a hash ({type: :integer, format: 'int32'})
76
+ if type_info.is_a?(Hash)
77
+ type_info.dup # Return a copy to avoid modifying the frozen hash
78
+ else
79
+ { type: type_info }
80
+ end
81
+ end
82
+
83
+ def build_array_schema(field, all_definitions, current_depth)
84
+ schema = { type: :array }
85
+
86
+ if field[:has_nested]
87
+ # Array items have nested schema (e.g., array of objects with defined properties)
88
+ # Filter by both depth and parent to get only this array's nested fields
89
+ nested_fields = all_definitions.select { |d| d[:depth] == current_depth + 1 && d[:parent] == field[:name] }
90
+
91
+ if nested_fields.any?
92
+ # Build nested schema for array items
93
+ nested_schema = build_schema(all_definitions, current_depth + 1, field[:name])
94
+ schema[:items] = nested_schema
95
+ else
96
+ # Has nested block but no fields found - default to object
97
+ type_info = TYPE_MAPPING[field[:sub_type]] || :object
98
+ schema[:items] = type_info.is_a?(Hash) ? type_info.dup : { type: type_info }
99
+ end
100
+ elsif field[:sub_type]
101
+ # Simple array with specified item type
102
+ type_info = TYPE_MAPPING[field[:sub_type]] || :string
103
+ schema[:items] = type_info.is_a?(Hash) ? type_info.dup : { type: type_info }
104
+ end
105
+
106
+ schema
107
+ end
108
+
109
+ def build_hash_schema(field, all_definitions, current_depth)
110
+ if field[:has_nested]
111
+ # Find nested fields for this specific hash (filter by parent)
112
+ nested_fields = all_definitions.select { |d| d[:depth] == current_depth + 1 && d[:parent] == field[:name] }
113
+
114
+ if nested_fields.any?
115
+ # Build nested schema
116
+ nested_schema = build_schema(all_definitions, current_depth + 1, field[:name])
117
+ return nested_schema
118
+ end
119
+ end
120
+
121
+ # Empty hash or hash without nested definition
122
+ { type: :object }
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,3 @@
1
+ module DryValidationOpenapi
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,8 @@
1
+ require_relative 'dry_validation_openapi/version'
2
+ require_relative 'dry_validation_openapi/contract_parser'
3
+ require_relative 'dry_validation_openapi/schema_builder'
4
+ require_relative 'dry_validation_openapi/convertable'
5
+
6
+ module DryValidationOpenapi
7
+ class Error < StandardError; end
8
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dry_validation_openapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - troptropcontent
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '13.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '13.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.12'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.12'
40
+ - !ruby/object:Gem::Dependency
41
+ name: dry-validation
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.10'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.10'
54
+ description: Automatically convert dry-validation contract definitions to OpenAPI
55
+ 3.0 schemas for use with rswag and other OpenAPI tools. Uses static parsing to extract
56
+ type information from contract params blocks.
57
+ email:
58
+ - troptropcontent@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - CHANGELOG.md
64
+ - LICENSE
65
+ - README.md
66
+ - lib/dry_validation_openapi.rb
67
+ - lib/dry_validation_openapi/contract_parser.rb
68
+ - lib/dry_validation_openapi/convertable.rb
69
+ - lib/dry_validation_openapi/schema_builder.rb
70
+ - lib/dry_validation_openapi/version.rb
71
+ homepage: https://github.com/troptropcontent/dry_validation_openapi
72
+ licenses:
73
+ - MIT
74
+ metadata:
75
+ homepage_uri: https://github.com/troptropcontent/dry_validation_openapi
76
+ source_code_uri: https://github.com/troptropcontent/dry_validation_openapi
77
+ changelog_uri: https://github.com/troptropcontent/dry_validation_openapi/blob/main/CHANGELOG.md
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: 3.1.0
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.6.9
93
+ specification_version: 4
94
+ summary: Generate OpenAPI schemas from dry-validation contracts
95
+ test_files: []