dry-swagger 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: 0ea8396c1d7976844254a7e7564a74a0cdc0391c3bf42a4aa49fc479fd99e11e
4
- data.tar.gz: 611a49427c0c0ece4bd4ec1e134afd8bcebc01f43b0803eecabdd9cf16df4d14
3
+ metadata.gz: 5179183ed4122bcf5042f8aa812b6830b1126ae00d4eb2975bd17203af2bf375
4
+ data.tar.gz: 9eb614eaaaca4752a39f9a77ef2fac3dffb4df2179a0c7e7f427d13f9f02333e
5
5
  SHA512:
6
- metadata.gz: 7d1e8404d230897c6f4e88fffbd1870ee1fbf305b725d8d9067f5529c3f2bcdda71990b364372478d3ff9f780e6a997144c557f57f574768d705caea10255923
7
- data.tar.gz: 0d7b5f769a536d9fd18b594cf097c5c9922b92f74bdf009ff2dd90ea099e90c5bc9d36aa684efcdd49a1176f299d6db2574a786a8a98213a5301a15bfdb223bf
6
+ metadata.gz: 58dea258473d5fea4c521d699a2332ec8a444d15504b81ff3eefba0ef50c08371fe5d9b3fd7e2d3331613375f625bdb3ea54073dde31cfc20eafdc0d29e49202
7
+ data.tar.gz: 2ec6862a8021cb836101cac89b394482507a6b48021cfbf304b63c8753fe0bcefb822730a194ae869da6c83dc34e965af771a58b6052dc729cea0d528a97b6a4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dry-swagger (0.3.0)
4
+ dry-swagger (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -33,7 +33,7 @@ Or install it yourself as:
33
33
  end
34
34
  end
35
35
 
36
- Dry::Swagger::ContractParser.new.call(Contract)
36
+ Dry::Swagger::ContractParser.new.call(Contract).to_swagger
37
37
  => {
38
38
  "type": "object",
39
39
  "properties": {
@@ -81,7 +81,7 @@ Or install it yourself as:
81
81
  end
82
82
  end
83
83
 
84
- Dry::Swagger::ContractParser.new.call(Contract)
84
+ Dry::Swagger::ContractParser.new.call(Contract).to_swagger
85
85
  => {
86
86
  "type": "object",
87
87
  "properties": {
@@ -135,7 +135,7 @@ Or install it yourself as:
135
135
  attribute? :optional_nullable_string, Types::String.optional
136
136
  end
137
137
 
138
- Dry::Swagger::StructParser.new.call(DTO)
138
+ Dry::Swagger::StructParser.new.call(DTO).to_swagger
139
139
  => {
140
140
  "type": "object",
141
141
  "properties": {
@@ -170,7 +170,22 @@ Or install it yourself as:
170
170
  ]
171
171
  }
172
172
  #### With nested fields
173
- {
173
+ class NestedDTO < Dry::Struct
174
+ attribute :required_string, Types::String
175
+ attribute :required_nullable_string, Types::String.optional
176
+ attribute :required_string_with_enum, Types::String.enum('enum1')
177
+ attribute? :optional_string, Types::String
178
+ attribute? :optional_nullable_string, Types::String.optional
179
+ end
180
+
181
+ class DTO < Dry::Struct
182
+ attribute :array_of_integer, Types::Array.of(Types::Integer)
183
+ attribute :array_of_objects, Types::Array.of(NestedDTO)
184
+ attribute :dto, NestedDTO
185
+ end
186
+
187
+ Dry::Swagger::StructParser.new.call(DTO).to_swagger
188
+ => {
174
189
  "type": "object",
175
190
  "properties": {
176
191
  "array_of_integer": {
@@ -258,21 +273,63 @@ Or install it yourself as:
258
273
  "dto"
259
274
  ]
260
275
  }
276
+ ## Overriding fields on run time
277
+ You can also modify the fields during runtime by passing a block after the .call() method.
278
+
279
+ For example:
280
+
281
+ Dry::Swagger::StructParser.new.call(DTO) do |it|
282
+ # types = string/integer/hash/array
283
+
284
+ # Remove a field
285
+ its.keys = it.keys.except(:field_name)
286
+
287
+ # Add new field on root level
288
+ it.keys[:new_field_name] = { type: type, required: true/false, :it.config.nullable_type=>true/false }
289
+
290
+ # Add a new field in nested hash/array
291
+ it.keys[:nested_field][:keys][:new_field_name] = {
292
+ type: type, required: true/false, :it.config.nullable_type=>true/false
293
+ }
294
+
295
+ # Remove a field in nested hash/array
296
+ it.keys = it.keys[:nested_field][:keys].except(:field_name)
297
+
298
+ # Add an array or hash
299
+ it.keys[:nested_field] = {
300
+ type: "array/hash", required: true/false, :it.config.nullable_type=> true/false, keys: {
301
+ # List all nested fields
302
+ new_field: { type: :type, required: true/false, :it.config.nullable_type=>true/false }
303
+ }
304
+ }
305
+
306
+ # Add an Array of primitive types, type field needs to be the element type(string, integer, float),
307
+ and add an array: true flag
308
+
309
+ it.keys[:array_field_name] = {
310
+ type: type, array: true, required: true/false, :it.config.nullable_type=> true/false
311
+ }
312
+
313
+ end.to_swagger()
261
314
  ## Custom Configuration For Your Project
262
315
  You can override default configurations by creating a file in config/initializers/dry-swagger.rb and changing the following values.
263
316
 
264
- Dry::Swagger.configuration do |config|
265
- config.struct_enable_required_validation = true / false
266
- config.struct_enable_nullable_validation = true / false
267
- config.struct_enable_enums = true / false
268
- config.struct_enable_descriptions = true / false
269
-
270
- config.contract_enable_required_validation = true / false
271
- config.contract_enable_nullable_validation = true / false
272
- config.contract_enable_enums = true / false
273
- config.contract_enable_descriptions = true / false
317
+ Dry::Swagger::Config::StructConfiguration.configuration do |config|
318
+ config.enable_required_validation = true / false
319
+ config.enable_nullable_validation = true / false
320
+ config.enable_enums = true / false
321
+ config.enable_descriptions = true / false
322
+ config.nullable_type = :"x-nullable" / :nullable
323
+ end
324
+
325
+ Dry::Swagger::Config::ContractConfiguration.configuration do |config|
326
+ config.enable_required_validation = true / false
327
+ config.enable_nullable_validation = true / false
328
+ config.enable_enums = true / false
329
+ config.enable_descriptions = true / false
274
330
  config.nullable_type = :"x-nullable" / :nullable
275
331
  end
332
+
276
333
  By default, all these settings are true, and nullable_type is :"x-nullable".
277
334
  ## Development
278
335
 
data/lib/dry/swagger.rb CHANGED
@@ -1,24 +1,14 @@
1
1
  require "dry/swagger/version"
2
2
  require "dry/swagger/contract_parser"
3
3
  require "dry/swagger/struct_parser"
4
- require 'helpers/configuration'
4
+ require 'dry/swagger/documentation_generator'
5
+ require 'dry/swagger/errors/missing_hash_schema_error'
6
+ require 'dry/swagger/errors/missing_type_error'
7
+ require 'dry/swagger/config/configuration'
8
+ require 'dry/swagger/config/contract_configuration'
9
+ require 'dry/swagger/config/struct_configuration'
5
10
 
6
11
  module Dry
7
12
  module Swagger
8
- class Error < StandardError; end
9
-
10
- extend Configuration
11
-
12
- define_setting :struct_enable_required_validation, true
13
- define_setting :struct_enable_nullable_validation, true
14
- define_setting :struct_enable_enums, true
15
- define_setting :struct_enable_descriptions, true
16
-
17
- define_setting :contract_enable_required_validation, true
18
- define_setting :contract_enable_nullable_validation, true
19
- define_setting :contract_enable_enums, true
20
- define_setting :contract_enable_descriptions, true
21
-
22
- define_setting :nullable_type, :"x-nullable"
23
13
  end
24
14
  end
@@ -0,0 +1,32 @@
1
+ module Dry
2
+ module Swagger
3
+ module Config
4
+ module Configuration
5
+ def configuration
6
+ yield self
7
+ end
8
+
9
+ def define_setting(name, default = nil)
10
+ class_variable_set("@@#{name}", default)
11
+
12
+ define_class_method "#{name}=" do |value|
13
+ class_variable_set("@@#{name}", value)
14
+ end
15
+
16
+ define_class_method name do
17
+ class_variable_get("@@#{name}")
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def define_class_method(name, &block)
24
+ (class << self; self; end).instance_eval do
25
+ define_method name, &block
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Dry
2
+ module Swagger
3
+ module Config
4
+ module ContractConfiguration
5
+ extend Configuration
6
+
7
+ define_setting :enable_required_validation, true
8
+ define_setting :enable_nullable_validation, true
9
+ define_setting :enable_enums, true
10
+ define_setting :enable_descriptions, true
11
+ define_setting :nullable_type, :"x-nullable"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Dry
2
+ module Swagger
3
+ module Config
4
+ module StructConfiguration
5
+ extend Configuration
6
+
7
+ define_setting :enable_required_validation, true
8
+ define_setting :enable_nullable_validation, true
9
+ define_setting :enable_enums, true
10
+ define_setting :enable_descriptions, true
11
+ define_setting :nullable_type, :"x-nullable"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -15,22 +15,13 @@ module Dry
15
15
  time?: 'time'
16
16
  }.freeze
17
17
 
18
- SWAGGER_FIELD_TYPE_DEFINITIONS = {
19
- "string" => { type: :string },
20
- "integer" => { type: :integer },
21
- "boolean" => { type: :boolean },
22
- "float" => { type: :float },
23
- "datetime" => { type: :string, format: :datetime },
24
- "date" => { type: :string, format: :date },
25
- "time" => { type: :string, format: :time },
26
- }.freeze
27
-
28
18
  # @api private
29
19
  attr_reader :keys
30
20
 
31
21
  # @api private
32
22
  def initialize
33
23
  @keys = {}
24
+ @config = Config::ContractConfiguration
34
25
  end
35
26
 
36
27
  # @api private
@@ -43,7 +34,7 @@ module Dry
43
34
  @keys = {}
44
35
  visit(contract.schema.to_ast)
45
36
  instance_eval(&block) if block_given?
46
- to_swagger
37
+ self
47
38
  end
48
39
 
49
40
  # @api private
@@ -75,14 +66,13 @@ module Dry
75
66
  end
76
67
 
77
68
  def visit_not(_node, opts = {})
78
- key = opts[:key]
79
- keys[key][::Dry::Swagger.nullable_type] = true if ::Dry::Swagger.contract_enable_nullable_validation
69
+ keys[opts[:key]][@config.nullable_type] = true
80
70
  end
81
71
 
82
72
  # @api private
83
73
  def visit_implication(node, opts = {})
84
74
  node.each do |el|
85
- opts = opts.merge(required: false) if ::Dry::Swagger.contract_enable_required_validation
75
+ opts = opts.merge(required: false)
86
76
  visit(el, opts)
87
77
  end
88
78
  end
@@ -96,7 +86,7 @@ module Dry
96
86
  def visit_key(node, opts = {})
97
87
  name, rest = node
98
88
  opts = opts.merge(key: name)
99
- opts = opts.merge(required: true) if ::Dry::Swagger.contract_enable_required_validation
89
+ opts = opts.merge(required: true)
100
90
  visit(rest, opts)
101
91
  end
102
92
 
@@ -107,11 +97,13 @@ module Dry
107
97
  key = opts[:key]
108
98
 
109
99
  if name.equal?(:key?)
110
- keys[rest[0][1]] = { required: opts.fetch(:required, true) } if ::Dry::Swagger.contract_enable_required_validation
100
+ keys[rest[0][1]] = { required: opts.fetch(:required, true) }
111
101
  elsif name.equal?(:array?)
112
102
  keys[key][:array] = true
113
103
  elsif name.equal?(:included_in?)
114
- keys[key][:enum] = rest[0][1]
104
+ enums = rest[0][1]
105
+ enums += [nil] if opts.fetch(@config.nullable_type, false)
106
+ keys[key][:enum] = enums
115
107
  elsif PREDICATE_TO_TYPE[name]
116
108
  keys[key][:type] = PREDICATE_TO_TYPE[name]
117
109
  else
@@ -139,34 +131,7 @@ module Dry
139
131
  end
140
132
 
141
133
  def to_swagger
142
- generate_documentation(keys)
143
- end
144
-
145
- private
146
-
147
- def generate_documentation(fields)
148
- documentation = { properties: {}, required: [] }
149
- fields.each do |field_name, attributes_hash|
150
- documentation[:properties][field_name] = generate_field_properties(attributes_hash)
151
- documentation[:required] << field_name if ::Dry::Swagger.contract_enable_required_validation && attributes_hash[:required]
152
- end
153
- { :type => :object, :properties => documentation[:properties], :required => documentation[:required] }
154
- end
155
-
156
- def generate_field_properties(attributes_hash)
157
- if attributes_hash[:type] == 'array'
158
- { type: :array, items: generate_documentation(attributes_hash[:keys]) }
159
- elsif attributes_hash[:array] && attributes_hash[:type] != 'array'
160
- { type: :array, items: SWAGGER_FIELD_TYPE_DEFINITIONS.fetch(attributes_hash[:type]) }
161
- elsif attributes_hash[:type] == 'hash'
162
- generate_documentation(attributes_hash[:keys])
163
- else
164
- field = SWAGGER_FIELD_TYPE_DEFINITIONS.fetch(attributes_hash[:type])
165
- field = field.merge(::Dry::Swagger.nullable_type => attributes_hash[::Dry::Swagger.nullable_type] | false) if ::Dry::Swagger.contract_enable_nullable_validation
166
- field = field.merge(enum: attributes_hash[:enum]) if attributes_hash[:enum] if ::Dry::Swagger.contract_enable_enums
167
- field = field.merge(description: attributes_hash[:description]) if attributes_hash[:description] if ::Dry::Swagger.contract_enable_descriptions
168
- field
169
- end
134
+ DocumentationGenerator.new(@config).generate_documentation(keys)
170
135
  end
171
136
  end
172
137
  end
@@ -0,0 +1,86 @@
1
+ module Dry
2
+ module Swagger
3
+ class DocumentationGenerator
4
+ SWAGGER_FIELD_TYPE_DEFINITIONS = {
5
+ "string" => { type: :string },
6
+ "integer" => { type: :integer },
7
+ "boolean" => { type: :boolean },
8
+ "float" => { type: :float },
9
+ "datetime" => { type: :string, format: :datetime },
10
+ "date" => { type: :string, format: :date },
11
+ "time" => { type: :string, format: :time },
12
+ }.freeze
13
+
14
+ def initialize(config)
15
+ @config = config
16
+ end
17
+
18
+ def generate_documentation(fields)
19
+ documentation = { properties: {}, required: [] }
20
+ fields.each do |field_name, attributes_hash|
21
+ documentation[:properties][field_name] = generate_field_properties(attributes_hash)
22
+ if attributes_hash.is_a?(Hash)
23
+ documentation[:required] << field_name if attributes_hash.fetch(:required, true) && @config.enable_required_validation
24
+ else
25
+ documentation[:required] << field_name if attributes_hash[0].fetch(:required, true) && @config.enable_required_validation
26
+ end
27
+
28
+ rescue Errors::MissingTypeError => e
29
+ raise StandardError.new e.message % { field_name: field_name, valid_types: SWAGGER_FIELD_TYPE_DEFINITIONS.keys, attributes_hash: attributes_hash }
30
+ rescue Errors::MissingHashSchemaError => e
31
+ raise StandardError.new e.message % { field_name: field_name, valid_types: SWAGGER_FIELD_TYPE_DEFINITIONS.keys, attributes_hash: attributes_hash }
32
+ end
33
+
34
+ { :type => :object, :properties => documentation[:properties], :required => documentation[:required] }
35
+ end
36
+
37
+ def generate_field_properties(attributes_hash)
38
+ if attributes_hash.is_a?(Array)
39
+ properties = {}
40
+ attributes_hash.each_with_index do |_, index|
41
+ properties["definition_#{index + 1}"] = generate_field_properties(attributes_hash[index])
42
+ end
43
+ {
44
+ oneOf: attributes_hash.map{ |it| generate_field_properties(it) },
45
+ type: :object,
46
+ properties: properties,
47
+ example: 'Dynamic Field. See Model Definitions'
48
+ }
49
+ else
50
+ if attributes_hash[:type] == 'array'
51
+ items = generate_documentation(attributes_hash.fetch(:keys))
52
+ items = @config.enable_nullable_validation ?
53
+ items.merge(@config.nullable_type => attributes_hash.fetch(@config.nullable_type, false)) :
54
+ items.merge(@config.nullable_type => true)
55
+ documentation = { type: :array, items: items }
56
+ elsif attributes_hash[:array] && attributes_hash.fetch(:type) != 'array'
57
+ items = SWAGGER_FIELD_TYPE_DEFINITIONS.fetch(attributes_hash.fetch(:type))
58
+ items = @config.enable_nullable_validation ?
59
+ items.merge(@config.nullable_type => attributes_hash.fetch(@config.nullable_type, false)) :
60
+ items.merge(@config.nullable_type => true)
61
+ documentation = { type: :array, items: items }
62
+ elsif attributes_hash[:type] == 'hash'
63
+ raise Errors::MissingHashSchemaError.new unless attributes_hash[:keys]
64
+ documentation = generate_documentation(attributes_hash.fetch(:keys))
65
+ else
66
+ documentation = SWAGGER_FIELD_TYPE_DEFINITIONS.fetch(attributes_hash.fetch(:type))
67
+ if attributes_hash[:enum] && @config.enable_enums
68
+ documentation = documentation.merge(enum: attributes_hash.fetch(:enum))
69
+ end
70
+
71
+ if attributes_hash[:description] && @config.enable_descriptions
72
+ documentation = documentation.merge(description: attributes_hash.fetch(:description))
73
+ end
74
+ end
75
+
76
+ @config.enable_nullable_validation ?
77
+ documentation.merge(@config.nullable_type => attributes_hash.fetch(@config.nullable_type, false)) :
78
+ documentation.merge(@config.nullable_type => true)
79
+ end
80
+
81
+ rescue KeyError
82
+ raise Errors::MissingTypeError.new
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,15 @@
1
+ module Dry
2
+ module Swagger
3
+ module Errors
4
+ class MissingHashSchemaError < StandardError
5
+ def message
6
+ "Could not generate documentation for field %{field_name}. The field is defined as hash,
7
+ but the schema is not defined.
8
+ Valid types are: %{valid_types}.
9
+ The parser has generated the following definition for the field: %{field_name}: %{attributes_hash}
10
+ "
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Dry
2
+ module Swagger
3
+ module Errors
4
+ class MissingTypeError < StandardError
5
+ def message
6
+ "Could not generate documentation for field %{field_name}. The field is missing a type.
7
+ If the field you have defined is an array, you must specify the type of the elements in that array.
8
+ Valid types are: %{valid_types}.
9
+ The parser has generated the following definition for the field: %{field_name}: %{attributes_hash}.
10
+ "
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,81 +1,144 @@
1
1
  module Dry
2
2
  module Swagger
3
3
  class StructParser
4
- SWAGGER_FIELD_TYPE_DEFINITIONS = {
5
- "String" => { type: :string },
6
- "Integer" => { type: :integer },
7
- "TrueClass | FalseClass" => { type: :boolean },
8
- "BigDecimal" => { type: :decimal },
9
- "Float" => { type: :float },
10
- "DateTime" => { type: :string, format: :datetime },
11
- "Date" => { type: :string, format: :date },
12
- "Time" => { type: :string, format: :time }
13
- }
14
-
15
- def call(dto)
16
- documentation = generate_fields_documentation(dto.schema)
17
- { :type => :object, :properties => documentation[:properties], :required => documentation[:required]}
4
+ PREDICATE_TYPES = {
5
+ String: 'string',
6
+ Integer: 'integer',
7
+ Bool: 'boolean',
8
+ Float: 'float',
9
+ Date: 'date',
10
+ DateTime: 'datetime',
11
+ Time: 'time'
12
+ }.freeze
13
+
14
+ attr_reader :keys
15
+
16
+ def initialize
17
+ @keys = {}
18
+ @config = Dry::Swagger::Config::StructConfiguration
18
19
  end
19
20
 
20
- def generate_fields_documentation(dto_schema)
21
- documentation = { properties: {}, required: [] }
22
- dto_schema.name_key_map.each do |name, schema_key_object|
23
- documentation[:properties][name] = schema_key_object.type.optional? ?
24
- generate_field_properties(schema_key_object.type.right, true) :
25
- generate_field_properties(schema_key_object.type, false)
21
+ def to_h
22
+ { keys: keys }
23
+ end
26
24
 
27
- documentation[:required] << name if ::Dry::Swagger.struct_enable_required_validation && schema_key_object.required?
28
- end
29
- documentation
25
+ def call(dto, &block)
26
+ @keys = {}
27
+ visit(dto.schema.to_ast)
28
+ instance_eval(&block) if block_given?
29
+ self
30
+ end
31
+
32
+ def visit(node, opts = {})
33
+ meth, rest = node
34
+ public_send(:"visit_#{meth}", rest, opts)
35
+ end
36
+
37
+ def visit_constructor(node, opts = {})
38
+ visit(node[0], opts)
30
39
  end
31
40
 
32
- def generate_field_properties(type, nullable)
33
- field_type = type.name
34
- if SWAGGER_FIELD_TYPE_DEFINITIONS[field_type] # IS PRIMITIVE FIELD?
35
- definition = SWAGGER_FIELD_TYPE_DEFINITIONS[field_type]
36
- definition = definition
37
- if is_enum?(type.class.name) && ::Dry::Swagger.struct_enable_enums
38
- enums = type.values
39
- enums += [nil] if nullable
40
- definition = definition.merge(enum: enums)
41
- end
42
- elsif is_array?(field_type)
43
- definition = { type: :array }
44
- if is_primitive?(type.type.member.name)
45
- definition = definition
46
- definition = definition.merge(items: SWAGGER_FIELD_TYPE_DEFINITIONS[type.type.member.name])
47
- else
48
- schema = is_array_with_dynamic_schema?(type.type.member) ? type.type.member.left : type.type.member
49
- definition = definition.merge(items: call(schema))
50
- end
41
+ def visit_schema(node, opts = {})
42
+ target = (key = opts[:key]) ? self.class.new : self
43
+
44
+ required = opts.fetch(:required, true)
45
+ nullable = opts.fetch(:nullable, false)
46
+
47
+ node[0].each do |child|
48
+ target.visit(child)
49
+ end
50
+
51
+ return unless key
52
+
53
+ target_info = target.to_h if opts[:member]
54
+
55
+ type = opts[:array]? 'array' : 'hash'
56
+
57
+ definition = {
58
+ type: type,
59
+ required: required,
60
+ @config.nullable_type => nullable,
61
+ **target_info
62
+ }
63
+
64
+ if opts[:oneOf]
65
+ keys[key] = keys[key] ? keys[key] << definition : [definition]
51
66
  else
52
- schema = is_dynamic_schema?(type) ? type.left : type
53
- definition = call(schema)
67
+ keys[key] = definition
54
68
  end
69
+ end
70
+
71
+ def visit_key(node, opts = {})
72
+ name, required, rest = node
73
+ opts[:key] = name
74
+ opts[:required] = required
75
+ visit(rest, opts)
76
+ end
55
77
 
56
- ::Dry::Swagger.struct_enable_nullable_validation ? definition.merge(::Dry::Swagger.nullable_type => nullable) : definition
78
+ def visit_constrained(node, opts = {})
79
+ node.each {|it| visit(it, opts) }
57
80
  end
58
81
 
59
- private
82
+ def visit_nominal(_node, _opts); end
83
+
84
+ def visit_predicate(node, opts = {})
85
+ name, rest = node
86
+ type = rest[0][1]
60
87
 
61
- def is_enum?(class_name)
62
- class_name == 'Dry::Types::Enum'
88
+ if name.equal?(:type?)
89
+ type = type.to_s.to_sym
90
+ return unless PREDICATE_TYPES[type]
91
+
92
+ type_definition = {
93
+ type: PREDICATE_TYPES[type],
94
+ required: opts.fetch(:required),
95
+ @config.nullable_type => opts.fetch(:nullable, false)
96
+ }
97
+
98
+ type_definition[:array] = opts[:array] if opts[:array]
99
+
100
+ keys[opts[:key]] = type_definition
101
+ elsif name.equal?(:included_in?)
102
+ type += [nil] if opts.fetch(:nullable, false)
103
+ keys[opts[:key]][:enum] = type
104
+ end
63
105
  end
64
106
 
65
- def is_array?(type_name)
66
- type_name == 'Array'
107
+ def visit_and(node, opts = {})
108
+ left, right = node
109
+
110
+ visit(left, opts)
111
+ visit(right, opts)
112
+ end
113
+
114
+ def visit_enum(node, opts = {})
115
+ visit(node[0], opts)
67
116
  end
68
117
 
69
- def is_primitive?(type_name)
70
- !SWAGGER_FIELD_TYPE_DEFINITIONS[type_name].nil?
118
+ def visit_sum(node, opts = {})
119
+ if node[0][0].equal?(:constrained)
120
+ opts[:nullable] = true
121
+ visit(node[1], opts) # ignore NilClass constrained
122
+ elsif node[0][0].equal?(:struct) && node[1][0].equal?(:struct)
123
+ opts[:oneOf] = true
124
+ visit(node[0], opts)
125
+ visit(node[1], opts)
126
+ end
127
+ end
128
+
129
+ def visit_struct(node, opts = {})
130
+ opts[:member] = true
131
+
132
+ visit(node[1], opts)
71
133
  end
72
134
 
73
- def is_array_with_dynamic_schema?(member)
74
- member.respond_to?(:right)
135
+ def visit_array(node, opts = {})
136
+ opts[:array] = true
137
+ visit(node[0], opts)
75
138
  end
76
139
 
77
- def is_dynamic_schema?(type)
78
- !type.respond_to?(:schema)
140
+ def to_swagger
141
+ DocumentationGenerator.new(@config).generate_documentation(keys)
79
142
  end
80
143
  end
81
144
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Swagger
3
- VERSION = "0.3.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-swagger
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
  - Jane-Terziev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-31 00:00:00.000000000 Z
11
+ date: 2021-08-03 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A parser which converts dry-validation or dry-struct into valid swagger
14
14
  documentation
@@ -32,11 +32,16 @@ files:
32
32
  - bin/setup
33
33
  - dry-swagger.gemspec
34
34
  - lib/dry/swagger.rb
35
+ - lib/dry/swagger/config/configuration.rb
36
+ - lib/dry/swagger/config/contract_configuration.rb
37
+ - lib/dry/swagger/config/struct_configuration.rb
35
38
  - lib/dry/swagger/contract_parser.rb
39
+ - lib/dry/swagger/documentation_generator.rb
40
+ - lib/dry/swagger/errors/missing_hash_schema_error.rb
41
+ - lib/dry/swagger/errors/missing_type_error.rb
36
42
  - lib/dry/swagger/struct_parser.rb
37
43
  - lib/dry/swagger/types.rb
38
44
  - lib/dry/swagger/version.rb
39
- - lib/helpers/configuration.rb
40
45
  homepage: https://github.com/Jane-Terziev/dry-swagger
41
46
  licenses:
42
47
  - MIT
@@ -1,27 +0,0 @@
1
- module Configuration
2
-
3
- def configuration
4
- yield self
5
- end
6
-
7
- def define_setting(name, default = nil)
8
- class_variable_set("@@#{name}", default)
9
-
10
- define_class_method "#{name}=" do |value|
11
- class_variable_set("@@#{name}", value)
12
- end
13
-
14
- define_class_method name do
15
- class_variable_get("@@#{name}")
16
- end
17
- end
18
-
19
- private
20
-
21
- def define_class_method(name, &block)
22
- (class << self; self; end).instance_eval do
23
- define_method name, &block
24
- end
25
- end
26
-
27
- end