jsapi 1.4.1 → 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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jsapi/controller/actions/class_methods.rb +61 -0
  3. data/lib/jsapi/controller/actions.rb +13 -0
  4. data/lib/jsapi/controller/authentication/class_methods.rb +65 -0
  5. data/lib/jsapi/controller/authentication/credentials/api_key.rb +24 -0
  6. data/lib/jsapi/controller/authentication/credentials/http/base.rb +25 -0
  7. data/lib/jsapi/controller/authentication/credentials/http/basic.rb +34 -0
  8. data/lib/jsapi/controller/authentication/credentials/http/bearer.rb +30 -0
  9. data/lib/jsapi/controller/authentication/credentials/http.rb +5 -0
  10. data/lib/jsapi/controller/authentication/credentials.rb +38 -0
  11. data/lib/jsapi/controller/authentication.rb +70 -0
  12. data/lib/jsapi/controller/base.rb +5 -4
  13. data/lib/jsapi/controller/methods/callbacks/callback.rb +80 -0
  14. data/lib/jsapi/controller/methods/callbacks/class_methods.rb +62 -0
  15. data/lib/jsapi/controller/methods/callbacks.rb +54 -0
  16. data/lib/jsapi/controller/methods.rb +188 -71
  17. data/lib/jsapi/controller/parameters.rb +24 -20
  18. data/lib/jsapi/controller/response.rb +71 -39
  19. data/lib/jsapi/controller.rb +2 -1
  20. data/lib/jsapi/dsl/base.rb +38 -5
  21. data/lib/jsapi/dsl/class_methods.rb +2 -2
  22. data/lib/jsapi/dsl/definitions.rb +41 -27
  23. data/lib/jsapi/dsl/operation.rb +10 -109
  24. data/lib/jsapi/dsl/parameter.rb +1 -1
  25. data/lib/jsapi/dsl/path.rb +41 -18
  26. data/lib/jsapi/dsl/request_body.rb +1 -1
  27. data/lib/jsapi/dsl/response.rb +9 -6
  28. data/lib/jsapi/dsl/schema.rb +11 -5
  29. data/lib/jsapi/dsl/shared_operation_methods.rb +140 -0
  30. data/lib/jsapi/dsl.rb +1 -2
  31. data/lib/jsapi/json/array.rb +2 -2
  32. data/lib/jsapi/json/object.rb +6 -6
  33. data/lib/jsapi/json.rb +4 -6
  34. data/lib/jsapi/media/range.rb +39 -6
  35. data/lib/jsapi/media/type.rb +8 -4
  36. data/lib/jsapi/media.rb +5 -0
  37. data/lib/jsapi/messages.rb +19 -0
  38. data/lib/jsapi/meta/callback/base.rb +63 -8
  39. data/lib/jsapi/meta/content.rb +59 -0
  40. data/lib/jsapi/meta/definitions.rb +291 -141
  41. data/lib/jsapi/meta/example/base.rb +41 -8
  42. data/lib/jsapi/meta/existence.rb +1 -1
  43. data/lib/jsapi/meta/header/base.rb +4 -2
  44. data/lib/jsapi/meta/info.rb +3 -1
  45. data/lib/jsapi/meta/license.rb +11 -5
  46. data/lib/jsapi/meta/model/attributes/class_methods.rb +150 -0
  47. data/lib/jsapi/meta/model/attributes/frozen_error.rb +16 -0
  48. data/lib/jsapi/meta/model/attributes/type_caster.rb +56 -0
  49. data/lib/jsapi/meta/model/attributes.rb +24 -118
  50. data/lib/jsapi/meta/model/base.rb +2 -5
  51. data/lib/jsapi/meta/model/reference.rb +46 -10
  52. data/lib/jsapi/meta/model/wrappable.rb +23 -0
  53. data/lib/jsapi/meta/model/wrapper.rb +26 -0
  54. data/lib/jsapi/meta/model.rb +2 -1
  55. data/lib/jsapi/meta/oauth_flow.rb +1 -1
  56. data/lib/jsapi/meta/openapi/extensions.rb +5 -6
  57. data/lib/jsapi/meta/openapi/version.rb +2 -2
  58. data/lib/jsapi/meta/operation.rb +177 -71
  59. data/lib/jsapi/meta/parameter/base.rb +9 -5
  60. data/lib/jsapi/meta/parameter/wrapper.rb +13 -0
  61. data/lib/jsapi/meta/parameter.rb +3 -0
  62. data/lib/jsapi/meta/path.rb +59 -13
  63. data/lib/jsapi/meta/pathname.rb +3 -0
  64. data/lib/jsapi/meta/property.rb +10 -0
  65. data/lib/jsapi/meta/request_body/base.rb +69 -32
  66. data/lib/jsapi/meta/request_body/wrapper.rb +13 -0
  67. data/lib/jsapi/meta/request_body.rb +3 -0
  68. data/lib/jsapi/meta/rescue_handler.rb +18 -17
  69. data/lib/jsapi/meta/response/base.rb +86 -49
  70. data/lib/jsapi/meta/response/reference.rb +11 -1
  71. data/lib/jsapi/meta/response/wrapper.rb +26 -0
  72. data/lib/jsapi/meta/response.rb +3 -0
  73. data/lib/jsapi/meta/schema/additional_properties.rb +8 -0
  74. data/lib/jsapi/meta/schema/array.rb +20 -8
  75. data/lib/jsapi/meta/schema/base.rb +10 -9
  76. data/lib/jsapi/meta/schema/numeric.rb +26 -20
  77. data/lib/jsapi/meta/schema/object.rb +60 -44
  78. data/lib/jsapi/meta/schema/reference.rb +1 -8
  79. data/lib/jsapi/meta/schema/string.rb +12 -6
  80. data/lib/jsapi/meta/schema/wrapper.rb +31 -0
  81. data/lib/jsapi/meta/schema.rb +22 -9
  82. data/lib/jsapi/meta/security_requirement.rb +2 -2
  83. data/lib/jsapi/meta/security_scheme/api_key.rb +5 -2
  84. data/lib/jsapi/meta/security_scheme/base.rb +7 -5
  85. data/lib/jsapi/meta/security_scheme/http/basic.rb +5 -7
  86. data/lib/jsapi/meta/security_scheme/http/bearer.rb +5 -5
  87. data/lib/jsapi/meta/security_scheme/http/other.rb +1 -3
  88. data/lib/jsapi/meta/security_scheme/mutual_tls.rb +1 -3
  89. data/lib/jsapi/meta/security_scheme/oauth2.rb +18 -13
  90. data/lib/jsapi/meta/security_scheme/open_id_connect.rb +4 -4
  91. data/lib/jsapi/meta/security_scheme.rb +4 -4
  92. data/lib/jsapi/meta/server.rb +4 -2
  93. data/lib/jsapi/meta/tag.rb +9 -3
  94. data/lib/jsapi/meta.rb +2 -1
  95. data/lib/jsapi/model/base.rb +1 -1
  96. data/lib/jsapi/status/base.rb +35 -0
  97. data/lib/jsapi/status/code.rb +113 -0
  98. data/lib/jsapi/status/default.rb +16 -0
  99. data/lib/jsapi/status/range.rb +35 -0
  100. data/lib/jsapi/status.rb +37 -0
  101. data/lib/jsapi/version.rb +1 -1
  102. data/lib/jsapi.rb +2 -3
  103. metadata +32 -10
  104. data/lib/jsapi/controller/parameters_invalid.rb +0 -27
  105. data/lib/jsapi/dsl/callback.rb +0 -21
  106. data/lib/jsapi/dsl/error.rb +0 -36
  107. data/lib/jsapi/invalid_argument_error.rb +0 -12
  108. data/lib/jsapi/invalid_value_error.rb +0 -12
  109. data/lib/jsapi/invalid_value_helper.rb +0 -17
  110. data/lib/jsapi/meta/model/type_caster.rb +0 -50
  111. data/lib/jsapi/meta/schema/delegator.rb +0 -26
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module DSL
5
+ module SharedOperationMethods
6
+ # Specifies the model class to access top-level parameters by.
7
+ #
8
+ # model Foo do
9
+ # def bar
10
+ # # ...
11
+ # end
12
+ # end
13
+ #
14
+ # +klass+ can be any subclass of Model::Base. If block is given, an anonymous
15
+ # class is created that inherits either from +klass+ or Model::Base.
16
+ #
17
+ # See Meta::Operation#model and Meta::Path#model for further information.
18
+ def model(klass = nil, &block)
19
+ if block
20
+ klass = Class.new(klass || Model::Base)
21
+ klass.class_eval(&block)
22
+ end
23
+ @meta_model.model = klass
24
+ end
25
+
26
+ # Specifies a parameter.
27
+ #
28
+ # parameter 'foo', type: 'string'
29
+ #
30
+ # parameter 'foo', type: 'object' do
31
+ # property 'bar', type: 'string'
32
+ # end
33
+ #
34
+ # Refers a resuable parameter if the +:ref+ keyword is specified.
35
+ #
36
+ # parameter ref: 'foo'
37
+ #
38
+ # Refers the reusable parameter with the same name if neither any
39
+ # keywords nor a block is specified.
40
+ #
41
+ # parameter 'foo'
42
+ #
43
+ # See Meta::Operation#parameters and Meta::Path#parameters for further
44
+ # information.
45
+ def parameter(name = nil, **keywords, &block)
46
+ define('parameter', name&.inspect) do
47
+ name = keywords[:ref] if name.nil?
48
+ keywords = { ref: name } unless keywords.any? || block
49
+
50
+ @meta_model.add_parameter(name, keywords).tap do |parameter_model|
51
+ Parameter.new(parameter_model, &block) if block
52
+ end
53
+ end
54
+ end
55
+
56
+ ##
57
+ # :call-seq:
58
+ # request_body(**keywords, &block)
59
+ # request_body(name)
60
+ #
61
+ # Specifies a request body.
62
+ #
63
+ # request_body type: 'object' do
64
+ # property 'foo', type: 'string'
65
+ # end
66
+ #
67
+ # Refers a resuable request body if the +:ref+ keyword is specified.
68
+ #
69
+ # request_body ref: 'foo'
70
+ #
71
+ # Refers the reusable request body with the same name if neither any
72
+ # keywords nor a block is specified.
73
+ #
74
+ # request_body 'foo'
75
+ #
76
+ # See Meta::Operation#request_body and Meta::Path#request_body for
77
+ # further information.
78
+ def request_body(name = nil, **keywords, &block)
79
+ define('request body') do
80
+ raise Error, "name can't be specified together with keywords or a block" \
81
+ if name && (keywords.any? || block)
82
+
83
+ keywords = { ref: name } if name
84
+ @meta_model.request_body = keywords
85
+
86
+ @meta_model.request_body.tap do |request_body|
87
+ RequestBody.new(request_body, &block) if block
88
+ end
89
+ end
90
+ end
91
+
92
+ ##
93
+ # :call-seq:
94
+ # response(status = nil, **keywords, &block)
95
+ # response(status, name)
96
+ # response(name)
97
+ #
98
+ # Specifies a response.
99
+ #
100
+ # response 200, type: 'object' do
101
+ # property 'foo', type: 'string'
102
+ # end
103
+ #
104
+ # The default status is <code>"default"</code>.
105
+ #
106
+ # Refers a resuable response if the +:ref+ keyword is specified.
107
+ #
108
+ # response 200, ref: 'foo'
109
+ #
110
+ # Refers the reusable response with the same name if neither any
111
+ # keywords nor a block is specified.
112
+ #
113
+ # response 'foo'
114
+ #
115
+ # See Meta::Operation#responses and Meta::Path#responses for further
116
+ # information.
117
+ def response(status = nil, name = nil, **keywords, &block)
118
+ define('response', status&.inspect) do
119
+ if keywords.none? && !block
120
+ status, name = nil, status unless name
121
+ keywords = { ref: name }
122
+ elsif name
123
+ raise Error, "name can't be specified together with keywords or a block"
124
+ end
125
+
126
+ @meta_model.add_response(status, keywords).tap do |response_model|
127
+ Response.new(response_model, &block) if block
128
+ end
129
+ end
130
+ end
131
+
132
+ ##
133
+ # :method: tag
134
+ # :args: name
135
+ # Specifies a tag.
136
+ #
137
+ # tag 'foo'
138
+ end
139
+ end
140
+ end
data/lib/jsapi/dsl.rb CHANGED
@@ -1,13 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'dsl/error'
4
3
  require_relative 'dsl/base'
5
4
  require_relative 'dsl/examples'
6
5
  require_relative 'dsl/schema'
7
6
  require_relative 'dsl/parameter'
8
7
  require_relative 'dsl/request_body'
9
8
  require_relative 'dsl/response'
10
- require_relative 'dsl/callback'
9
+ require_relative 'dsl/shared_operation_methods'
11
10
  require_relative 'dsl/operation'
12
11
  require_relative 'dsl/path'
13
12
  require_relative 'dsl/definitions'
@@ -4,10 +4,10 @@ module Jsapi
4
4
  module JSON
5
5
  # Represents a JSON array.
6
6
  class Array < Value
7
- def initialize(array, schema, definitions, context: nil)
7
+ def initialize(array, schema, context: nil)
8
8
  super(schema)
9
9
  @json_values = Array(array).map do |item|
10
- JSON.wrap(item, schema.items, definitions, context: context)
10
+ JSON.wrap(item, schema.items, context: context)
11
11
  end
12
12
  end
13
13
 
@@ -10,20 +10,20 @@ module Jsapi
10
10
 
11
11
  attr_reader :raw_additional_attributes, :raw_attributes
12
12
 
13
- def initialize(hash, schema, definitions, context: nil)
14
- schema = schema.resolve_schema(hash, definitions, context: context)
15
- properties = schema.resolve_properties(definitions, context: context)
13
+ def initialize(hash, schema, context: nil)
14
+ schema = schema.resolve_schema(hash, context: context)
15
+ properties = schema.resolve_properties(context: context)
16
16
 
17
17
  @raw_attributes = properties.transform_values do |property|
18
- JSON.wrap(hash[property.name], property.schema, definitions, context: context)
18
+ JSON.wrap(hash[property.name], property.schema, context: context)
19
19
  end
20
20
 
21
21
  @raw_additional_attributes =
22
22
  if (additional_properties = schema.additional_properties)
23
- additional_properties_schema = additional_properties.schema.resolve(definitions)
23
+ additional_properties_schema = additional_properties.schema
24
24
 
25
25
  hash.except(*properties.keys).transform_values do |value|
26
- JSON.wrap(value, additional_properties_schema, definitions, context: context)
26
+ JSON.wrap(value, additional_properties_schema, context: context)
27
27
  end
28
28
  end || {}
29
29
 
data/lib/jsapi/json.rb CHANGED
@@ -13,15 +13,13 @@ module Jsapi
13
13
  # Provides a DOM for JSON values.
14
14
  module JSON
15
15
  class << self
16
- def wrap(object, schema, definitions = nil, context: nil)
17
- schema = schema.resolve(definitions) unless definitions.nil?
18
-
19
- object = schema.default_value(definitions, context: context) if object.nil?
16
+ def wrap(object, schema, context: nil)
17
+ object = schema.default_value(context: context) if object.nil?
20
18
  return Null.new(schema) if object.nil?
21
19
 
22
20
  case schema.type
23
21
  when 'array'
24
- Array.new(object, schema, definitions, context: context)
22
+ Array.new(object, schema, context: context)
25
23
  when 'boolean'
26
24
  Boolean.new(object, schema)
27
25
  when 'integer'
@@ -29,7 +27,7 @@ module Jsapi
29
27
  when 'number'
30
28
  Number.new(object, schema)
31
29
  when 'object'
32
- Object.new(object, schema, definitions, context: context)
30
+ Object.new(object, schema, context: context)
33
31
  when 'string'
34
32
  String.new(object, schema)
35
33
  else
@@ -9,10 +9,16 @@ module Jsapi
9
9
  include Comparable
10
10
  include TypeAndSubtype
11
11
 
12
+ # Range for all types (<code>"\*/\*"</code>).
13
+ ALL = Range.new('*', '*')
14
+
15
+ # Range for \JSON type (<code>"application/json"</code>).
16
+ APPLICATION_JSON = Range.new('application', 'json')
17
+
12
18
  class << self
13
19
  # Transforms +value+ to an instance of this class.
14
20
  #
15
- # Raises an ArgumentError when +value+ could not be transformed.
21
+ # Raises an +ArgumentError+ when +value+ could not be transformed.
16
22
  def from(value)
17
23
  media_range = try_from(value)
18
24
  return media_range unless media_range.nil?
@@ -20,8 +26,21 @@ module Jsapi
20
26
  raise ArgumentError, "invalid media range: #{value.inspect}"
21
27
  end
22
28
 
23
- # Tries to transform +value+ to an instance of this class. Returns nil
24
- # if +value+ could not be transformed.
29
+ # Reduces the given collection of media ranges by removing media ranges
30
+ # that are already covered by another media range.
31
+ def reduce(media_ranges)
32
+ media_ranges.each_with_object([]) do |media_range, memo|
33
+ media_range = from(media_range)
34
+ if memo.none? { |other| other.cover?(media_range) }
35
+ memo.delete_if { |other| media_range.cover?(other) }
36
+ memo << media_range
37
+ end
38
+ end.sort
39
+ end
40
+
41
+ # Tries to transform +value+ to an instance of this class.
42
+ #
43
+ # Returns nil if +value+ could not be transformed.
25
44
  def try_from(value)
26
45
  return value if value.is_a?(Range)
27
46
 
@@ -52,14 +71,28 @@ module Jsapi
52
71
  subtype <=> other.subtype
53
72
  end
54
73
 
74
+ # Returns true if it covers +other+.
75
+ def cover?(other)
76
+ return if other.nil?
77
+
78
+ other = Range.from(other)
79
+
80
+ (type == '*' || type == other.type) &&
81
+ (subtype == '*' || subtype == other.subtype)
82
+ end
83
+
55
84
  # Returns true if the given media type matches the media range.
56
85
  def match?(media_type)
57
- media_type = Type.from(media_type) unless media_type.nil?
86
+ return if media_type.nil?
58
87
 
59
- (type == '*' || type == media_type&.type) &&
60
- (subtype == '*' || subtype == media_type&.subtype)
88
+ media_type = Type.from(media_type)
89
+
90
+ (type == '*' || type == media_type.type) &&
91
+ (subtype == '*' || subtype == media_type.subtype)
61
92
  end
62
93
 
94
+ alias =~ match?
95
+
63
96
  # Returns the level of priority of the media range.
64
97
  def priority
65
98
  @priority ||= (type == '*' ? 2 : 0) + (subtype == '*' ? 1 : 0) + 1
@@ -9,12 +9,15 @@ module Jsapi
9
9
  include Comparable
10
10
  include TypeAndSubtype
11
11
 
12
- # The <code>"application/json"</code> media type.
12
+ # Media::Type for <code>"application/json"</code>.
13
13
  APPLICATION_JSON = Type.new('application', 'json')
14
14
 
15
- # The <code>"application/json-seq"</code> media type.
15
+ # Media::Type for <code>"application/json-seq"</code>.
16
16
  APPLICATION_JSON_SEQ = Type.new('application', 'json-seq')
17
17
 
18
+ # Media::Type for <code>"text/plain"</code>.
19
+ TEXT_PLAIN = Type.new('text', 'plain')
20
+
18
21
  class << self
19
22
  # Transforms +value+ to an instance of this class.
20
23
  #
@@ -26,8 +29,9 @@ module Jsapi
26
29
  raise ArgumentError, "invalid media type: #{value.inspect}"
27
30
  end
28
31
 
29
- # Tries to transform +value+ to an instance of this class. Returns nil
30
- # if +value+ could not be transformed.
32
+ # Tries to transform +value+ to an instance of this class.
33
+ #
34
+ # Returns nil if +value+ could not be transformed.
31
35
  def try_from(value)
32
36
  return value if value.is_a?(Type)
33
37
 
data/lib/jsapi/media.rb CHANGED
@@ -2,3 +2,8 @@
2
2
 
3
3
  require_relative 'media/range'
4
4
  require_relative 'media/type'
5
+
6
+ module Jsapi
7
+ # Provides classes to deal with media types.
8
+ module Media end
9
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module Messages # :nodoc:
5
+ class << self
6
+ def invalid_value(name:, value:, valid_values: [])
7
+ case valid_values.count
8
+ when 0
9
+ "#{name} must not be #{value.inspect}"
10
+ when 1
11
+ "#{name} must be #{valid_values.first.inspect}, is #{value.inspect}"
12
+ else
13
+ "#{name} must be one of #{valid_values[0..-2].map(&:inspect).join(', ')} " \
14
+ "or #{valid_values.last.inspect}, is #{value.inspect}"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,28 +2,83 @@
2
2
 
3
3
  module Jsapi
4
4
  module Meta
5
+ module Parameter; end
5
6
  class Operation < Model::Base; end
6
7
 
7
8
  module Callback
8
9
  # Specifies a callback. Applies to \OpenAPI 3.0 and higher.
9
10
  class Base < Model::Base
11
+ # The set of operations that can be called backed.
12
+ class Operations < Model::Base
13
+ ##
14
+ # :attr: description
15
+ # The description that applies to all operations.
16
+ attribute :description, String
17
+
18
+ ##
19
+ # :attr: operations
20
+ # The operations. Maps strings to Operation objects.
21
+ attribute :operations, { String => Operation }, accessors: %i[reader writer]
22
+
23
+ ##
24
+ # :attr: parameters
25
+ # The parameters that apply for all operations. Maps parameter names
26
+ # to Parameter objects or references.
27
+ attribute :parameters, { String => Parameter }, accessors: %i[reader writer]
28
+
29
+ ##
30
+ # :attr: summary
31
+ # The short summary that applies to all operations.
32
+ attribute :summary, String
33
+
34
+ def add_operation(method = nil, keywords = {}) # :nodoc:
35
+ try_modify_attribute!(:operations) do
36
+ method, keywords = nil, method if method.is_a?(Hash)
37
+ method = 'get' if method.nil?
38
+
39
+ (@operations ||= {})[method] = Operation.new(nil, keywords.merge(method: method))
40
+ end
41
+ end
42
+
43
+ def add_parameter(name, keywords = {}) # :nodoc:
44
+ try_modify_attribute!(:parameters) do
45
+ name = name.to_s
46
+
47
+ (@parameters ||= {})[name] = Parameter.new(name, keywords)
48
+ end
49
+ end
50
+
51
+ # Returns a hash representing the \OpenAPI path item object that describes
52
+ # the operations.
53
+ def to_openapi(version, definitions)
54
+ OpenAPI::PathItem.new(
55
+ operations.values,
56
+ description: description,
57
+ summary: summary,
58
+ parameters: parameters
59
+ ).to_openapi(version, definitions)
60
+ end
61
+ end
62
+
10
63
  ##
11
- # :attr: operations
12
- attribute :operations, { String => Operation }, accessors: %i[reader writer]
64
+ # :attr: expressions
65
+ attribute :expressions, { String => Operations }, accessors: %i[reader writer]
13
66
 
14
- # Adds a callback operation.
67
+ # Adds an expression.
15
68
  #
16
69
  # Raises an +ArgumentError+ if +expression+ is blank.
17
- def add_operation(expression, keywords = {})
18
- raise ArgumentError, "expression can't be blank" if expression.blank?
70
+ def add_expression(expression, keywords = {})
71
+ try_modify_attribute!(:expressions) do
72
+ raise ArgumentError, "expression can't be blank" if expression.blank?
19
73
 
20
- (@operations ||= {})[expression.to_s] = Operation.new(nil, keywords)
74
+ (@expressions ||= {})[expression.to_s] = Operations.new(keywords)
75
+ end
21
76
  end
22
77
 
23
78
  # Returns a hash representing the \OpenAPI callback object.
24
79
  def to_openapi(version, definitions)
25
- operations.transform_values do |operation|
26
- OpenAPI::PathItem.new([operation]).to_openapi(version, definitions)
80
+ expressions.transform_values do |operations|
81
+ operations.to_openapi(version, definitions)
27
82
  end
28
83
  end
29
84
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module Meta
5
+ # Specifies the content of a request body or response.
6
+ class Content < Model::Base
7
+ include OpenAPI::Extensions
8
+
9
+ class Wrapper < Model::Wrapper
10
+ def schema
11
+ @schema ||= Schema.wrap(super, definitions)
12
+ end
13
+ end
14
+
15
+ include Model::Wrappable
16
+
17
+ delegate_missing_to :schema
18
+
19
+ ##
20
+ # :attr: examples
21
+ # The examples. Maps example names to Example objects or references.
22
+ attribute :examples, { String => Example }, default_key: 'default'
23
+
24
+ ##
25
+ # :attr_reader: schema
26
+ # The Schema of the content.
27
+ attribute :schema, accessors: %i[reader]
28
+
29
+ def initialize(keywords = {})
30
+ keywords = keywords.dup
31
+ super(keywords.extract!(:examples, :openapi_extensions))
32
+
33
+ add_example(value: keywords.delete(:example)) if keywords.key?(:example)
34
+ keywords[:ref] = keywords.delete(:schema) if keywords.key?(:schema)
35
+
36
+ @schema = Schema.new(keywords)
37
+ end
38
+
39
+ # Returns a hash representing the \OpenAPI media type object describing
40
+ # the content. Applies to \OpenAPI 3.0 and higher.
41
+ def to_openapi(version, media_type = nil)
42
+ version = OpenAPI::Version.from(version)
43
+
44
+ with_openapi_extensions(
45
+ **if media_type == Media::Type::APPLICATION_JSON_SEQ &&
46
+ schema.array? && version >= OpenAPI::V3_2
47
+ { itemSchema: schema.items.to_openapi(version) }
48
+ else
49
+ { schema: schema.to_openapi(version) }
50
+ end,
51
+ examples:
52
+ examples.transform_values do |example|
53
+ example.to_openapi(version)
54
+ end.presence
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end