jsapi 1.4 → 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 (113) 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 +209 -116
  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 +102 -0
  35. data/lib/jsapi/media/type.rb +70 -0
  36. data/lib/jsapi/media/type_and_subtype.rb +38 -0
  37. data/lib/jsapi/media.rb +9 -0
  38. data/lib/jsapi/messages.rb +19 -0
  39. data/lib/jsapi/meta/callback/base.rb +63 -8
  40. data/lib/jsapi/meta/content.rb +59 -0
  41. data/lib/jsapi/meta/definitions.rb +299 -153
  42. data/lib/jsapi/meta/example/base.rb +41 -8
  43. data/lib/jsapi/meta/existence.rb +4 -2
  44. data/lib/jsapi/meta/header/base.rb +4 -2
  45. data/lib/jsapi/meta/info.rb +3 -1
  46. data/lib/jsapi/meta/license.rb +11 -5
  47. data/lib/jsapi/meta/model/attributes/class_methods.rb +150 -0
  48. data/lib/jsapi/meta/model/attributes/frozen_error.rb +16 -0
  49. data/lib/jsapi/meta/model/attributes/type_caster.rb +56 -0
  50. data/lib/jsapi/meta/model/attributes.rb +24 -118
  51. data/lib/jsapi/meta/model/base.rb +2 -5
  52. data/lib/jsapi/meta/model/reference.rb +46 -10
  53. data/lib/jsapi/meta/model/wrappable.rb +23 -0
  54. data/lib/jsapi/meta/model/wrapper.rb +26 -0
  55. data/lib/jsapi/meta/model.rb +2 -1
  56. data/lib/jsapi/meta/oauth_flow.rb +1 -1
  57. data/lib/jsapi/meta/openapi/extensions.rb +5 -6
  58. data/lib/jsapi/meta/openapi/version.rb +16 -4
  59. data/lib/jsapi/meta/operation.rb +177 -71
  60. data/lib/jsapi/meta/parameter/base.rb +10 -6
  61. data/lib/jsapi/meta/parameter/wrapper.rb +13 -0
  62. data/lib/jsapi/meta/parameter.rb +3 -0
  63. data/lib/jsapi/meta/path.rb +59 -13
  64. data/lib/jsapi/meta/pathname.rb +6 -3
  65. data/lib/jsapi/meta/property.rb +10 -0
  66. data/lib/jsapi/meta/request_body/base.rb +69 -32
  67. data/lib/jsapi/meta/request_body/wrapper.rb +13 -0
  68. data/lib/jsapi/meta/request_body.rb +3 -0
  69. data/lib/jsapi/meta/rescue_handler.rb +18 -17
  70. data/lib/jsapi/meta/response/base.rb +82 -58
  71. data/lib/jsapi/meta/response/reference.rb +11 -1
  72. data/lib/jsapi/meta/response/wrapper.rb +26 -0
  73. data/lib/jsapi/meta/response.rb +3 -0
  74. data/lib/jsapi/meta/schema/additional_properties.rb +8 -0
  75. data/lib/jsapi/meta/schema/array.rb +20 -8
  76. data/lib/jsapi/meta/schema/base.rb +10 -9
  77. data/lib/jsapi/meta/schema/boundary.rb +1 -0
  78. data/lib/jsapi/meta/schema/numeric.rb +26 -20
  79. data/lib/jsapi/meta/schema/object.rb +60 -44
  80. data/lib/jsapi/meta/schema/reference.rb +1 -8
  81. data/lib/jsapi/meta/schema/string.rb +12 -6
  82. data/lib/jsapi/meta/schema/wrapper.rb +31 -0
  83. data/lib/jsapi/meta/schema.rb +22 -9
  84. data/lib/jsapi/meta/security_requirement.rb +2 -2
  85. data/lib/jsapi/meta/security_scheme/api_key.rb +5 -2
  86. data/lib/jsapi/meta/security_scheme/base.rb +7 -5
  87. data/lib/jsapi/meta/security_scheme/http/basic.rb +5 -7
  88. data/lib/jsapi/meta/security_scheme/http/bearer.rb +5 -5
  89. data/lib/jsapi/meta/security_scheme/http/other.rb +1 -3
  90. data/lib/jsapi/meta/security_scheme/mutual_tls.rb +1 -3
  91. data/lib/jsapi/meta/security_scheme/oauth2.rb +18 -13
  92. data/lib/jsapi/meta/security_scheme/open_id_connect.rb +4 -4
  93. data/lib/jsapi/meta/security_scheme.rb +4 -4
  94. data/lib/jsapi/meta/server.rb +4 -2
  95. data/lib/jsapi/meta/tag.rb +9 -3
  96. data/lib/jsapi/meta.rb +2 -1
  97. data/lib/jsapi/model/base.rb +1 -1
  98. data/lib/jsapi/status/base.rb +35 -0
  99. data/lib/jsapi/status/code.rb +113 -0
  100. data/lib/jsapi/status/default.rb +16 -0
  101. data/lib/jsapi/status/range.rb +35 -0
  102. data/lib/jsapi/status.rb +37 -0
  103. data/lib/jsapi/version.rb +1 -1
  104. data/lib/jsapi.rb +3 -3
  105. metadata +36 -10
  106. data/lib/jsapi/controller/parameters_invalid.rb +0 -27
  107. data/lib/jsapi/dsl/callback.rb +0 -21
  108. data/lib/jsapi/dsl/error.rb +0 -36
  109. data/lib/jsapi/invalid_argument_error.rb +0 -12
  110. data/lib/jsapi/invalid_value_error.rb +0 -12
  111. data/lib/jsapi/invalid_value_helper.rb +0 -17
  112. data/lib/jsapi/meta/model/type_caster.rb +0 -50
  113. data/lib/jsapi/meta/schema/delegator.rb +0 -26
@@ -7,70 +7,107 @@ module Jsapi
7
7
  class Base < Model::Base
8
8
  include OpenAPI::Extensions
9
9
 
10
- delegate_missing_to :schema
10
+ # To still allow to specify content-related directives within blocks
11
+ delegate_missing_to :last_content
11
12
 
12
13
  ##
13
- # :attr: content_type
14
- # The content type. <code>"application/json"</code> by default.
15
- attribute :content_type, String, default: 'application/json'
14
+ # :attr_reader: contents
15
+ # The alternative contents of the request body. Maps instances of
16
+ # Media::Range to Content objects.
17
+ attribute :contents, { Media::Range => Content }, accessors: %i[reader writer]
16
18
 
17
19
  ##
18
20
  # :attr: description
19
21
  # The description of the request body.
20
22
  attribute :description, String
21
23
 
22
- ##
23
- # :attr_reader: examples
24
- # The Example objects.
25
- attribute :examples, { String => Example }, default_key: 'default'
26
-
27
- ##
28
- # :attr_reader: schema
29
- # The Schema of the request body.
30
- attribute :schema, accessors: %i[reader]
31
-
32
24
  def initialize(keywords = {})
33
25
  keywords = keywords.dup
34
- super(keywords.extract!(:content_type, :description, :examples, :openapi_extensions))
26
+ content_keywords = keywords.slice!(*self.class.attribute_names)
27
+
28
+ # Move content-related keywords to :contents so that the first
29
+ # key-value pair in @contents is created from them.
30
+ if content_keywords.present?
31
+ content_type = content_keywords.delete(:content_type)
35
32
 
36
- add_example(value: keywords.delete(:example)) if keywords.key?(:example)
37
- keywords[:ref] = keywords.delete(:schema) if keywords.key?(:schema)
33
+ (keywords[:contents] ||= {}).reverse_merge!(
34
+ { content_type => content_keywords }
35
+ )
36
+ end
37
+ super(keywords)
38
+ end
38
39
 
39
- @schema = Schema.new(keywords)
40
+ def attribute_changed(name) # :nodoc:
41
+ @default_media_range = @default_content = @sorted_contents = nil if name == :contents
42
+ super
40
43
  end
41
44
 
42
- # Returns true if the level of existence is greater than or equal to
43
- # +ALLOW_NIL+, false otherwise.
44
- def required?
45
- schema.existence >= Existence::ALLOW_NIL
45
+ def add_content(media_range = nil, keywords = {}) # :nodoc:
46
+ try_modify_attribute!(:contents) do
47
+ media_range, keywords = nil, media_range if media_range.is_a?(Hash)
48
+ media_range = Media::Range.from(media_range || Media::Range::APPLICATION_JSON)
49
+
50
+ (@contents ||= {})[media_range] = Content.new(keywords)
51
+ end
46
52
  end
47
53
 
48
- # Returns a hash representing the \OpenAPI 2.0 parameter object.
54
+ # Returns the most appropriate content for the given media type.
55
+ def content_for(media_type)
56
+ (@sorted_contents ||= contents.sort)
57
+ .find { |media_range, _content| media_range =~ media_type }
58
+ &.second || default_content
59
+ end
60
+
61
+ def default_content
62
+ @default_content ||= contents.values.first
63
+ end
64
+
65
+ def default_media_range
66
+ @default_media_range = contents.keys.first
67
+ end
68
+
69
+ def freeze_attributes # :nodoc:
70
+ add_content if contents.blank?
71
+ super
72
+ end
73
+
74
+ # Returns a hash representing the \OpenAPI parameter object.
75
+ #
76
+ # Applies to \OpenAPI 2.0.
49
77
  def to_openapi_parameter
78
+ schema = default_content.schema
79
+
50
80
  with_openapi_extensions(
51
81
  {
52
82
  name: 'body',
53
83
  in: 'body',
54
84
  description: description,
55
- required: required?,
85
+ required: schema.existence >= Existence::ALLOW_NIL,
56
86
  **schema.to_openapi(OpenAPI::V2_0)
57
87
  }
58
88
  )
59
89
  end
60
90
 
61
- # Returns a hash representing the \OpenAPI 3.x request body object.
91
+ # Returns a hash representing the \OpenAPI request body object.
92
+ #
93
+ # Applies to \OpenAPI 3.0 and higher.
62
94
  def to_openapi(version, *)
63
95
  with_openapi_extensions(
64
96
  description: description,
65
- content: {
66
- content_type => {
67
- schema: schema.to_openapi(version),
68
- examples: examples.transform_values(&:to_openapi).presence
69
- }.compact
70
- },
71
- required: required?
97
+ content: contents.transform_values do |content|
98
+ content.to_openapi(version)
99
+ end,
100
+ required: contents.values.all? do |content|
101
+ content.schema.existence >= Existence::ALLOW_NIL
102
+ end
72
103
  )
73
104
  end
105
+
106
+ private
107
+
108
+ def last_content
109
+ contents.values.last || add_content
110
+ end
74
111
  end
75
112
  end
76
113
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module Meta
5
+ module RequestBody
6
+ class Wrapper < Model::Wrapper
7
+ def content_for(media_type)
8
+ Content.wrap(super, definitions)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,10 +2,13 @@
2
2
 
3
3
  require_relative 'request_body/base'
4
4
  require_relative 'request_body/reference'
5
+ require_relative 'request_body/wrapper'
5
6
 
6
7
  module Jsapi
7
8
  module Meta
8
9
  module RequestBody
10
+ include Model::Wrappable
11
+
9
12
  class << self
10
13
  # Creates a Base or Reference.
11
14
  def new(keywords = {})
@@ -2,31 +2,32 @@
2
2
 
3
3
  module Jsapi
4
4
  module Meta
5
- # Maps an error class to a response status.
5
+ # Specifies a rescue handler.
6
6
  class RescueHandler < Model::Base
7
7
  ##
8
8
  # :attr: error_class
9
- # The error class to be mapped.
10
- attribute :error_class, default: StandardError
9
+ # The error class to be rescued.
10
+ attribute :error_class, default: StandardError, accessors: %i[reader]
11
11
 
12
12
  ##
13
- # :attr: status
14
- # The response status. The default is <code>"default"</code>.
15
- attribute :status, default: 'default'
13
+ # :attr: status_code
14
+ # The Status::Code replacing the original status code when rescuing an
15
+ # instance of error_class.
16
+ attribute :status_code, Status::Code
16
17
 
17
- def initialize(keywords = {})
18
- super
19
- unless error_class.is_a?(Class)
20
- raise ArgumentError, "#{error_class.inspect} isn't a class"
21
- end
22
- unless error_class <= StandardError
23
- raise ArgumentError, "#{error_class.inspect} isn't a rescuable class"
24
- end
18
+ def error_class=(klass) # :nodoc:
19
+ raise ArgumentError, "#{klass.inspect} isn't a class" \
20
+ unless klass.is_a?(Class)
21
+
22
+ raise ArgumentError, "#{klass.inspect} isn't a rescuable class" \
23
+ unless klass <= StandardError
24
+
25
+ @error_class = klass
25
26
  end
26
27
 
27
- # Returns true if +exception+ is an instance of the class to be mapped, false otherwise.
28
- def match?(exception)
29
- exception.is_a?(error_class)
28
+ # Returns true if +error+ is an instance of error_class.
29
+ def match?(error)
30
+ error.is_a?(error_class)
30
31
  end
31
32
  end
32
33
  end
@@ -7,74 +7,94 @@ module Jsapi
7
7
  class Base < Model::Base
8
8
  include OpenAPI::Extensions
9
9
 
10
- JSON_TYPE = %r{(^application/|^text/|\+)json$}.freeze # :nodoc:
11
- JSON_SEQ_TYPE = 'application/json-seq' # :nodoc:
12
-
13
- delegate_missing_to :schema
10
+ # To still allow to specify content-related directives within blocks
11
+ delegate_missing_to :last_content
14
12
 
15
13
  ##
16
- # :attr: content_type
17
- # The content type, <code>"application/json"</code> by default.
18
- attribute :content_type, String, default: 'application/json'
14
+ # :attr_reader: contents
15
+ # The alternative contents of the response. Maps instances of
16
+ # Media::Range to Content objects.
17
+ attribute :contents, { Media::Type => Content }, accessors: %i[reader writer]
19
18
 
20
19
  ##
21
20
  # :attr: description
22
21
  # The description of the response.
23
22
  attribute :description, String
24
23
 
25
- ##
26
- # :attr: examples
27
- # The Example objects.
28
- attribute :examples, { String => Example }, default_key: 'default'
29
-
30
24
  ##
31
25
  # :attr: headers
32
- # The Header objects.
26
+ # The headers of the response. Maps header names to Header objects or
27
+ # references.
33
28
  attribute :headers, { String => Header }
34
29
 
35
30
  ##
36
31
  # :attr: links
37
- # The Link objects.
32
+ # The linked operations. Maps link names to Link objects.
38
33
  attribute :links, { String => Link }
39
34
 
40
35
  ##
41
36
  # :attr: locale
42
- # The locale used when rendering a response.
37
+ # The locale to be used instead of the default locale when rendering
38
+ # a response.
43
39
  attribute :locale, Symbol
44
40
 
45
41
  ##
46
- # :attr_reader: schema
47
- # The Schema of the response.
48
- attribute :schema, accessors: %i[reader]
42
+ # :attr: nodoc
43
+ # Prevents the response to be described in generated \OpenAPI documents.
44
+ attribute :nodoc, values: [true, false], default: false
49
45
 
50
46
  ##
51
47
  # :attr: summary
52
- # The short description of the response. Applies to \OpenAPI 3.2 and higher.
48
+ # The short description of the response.
49
+ #
50
+ # Applies to \OpenAPI 3.2 and higher.
53
51
  attribute :summary, String
54
52
 
55
53
  def initialize(keywords = {})
56
54
  keywords = keywords.dup
57
- super(
58
- keywords.extract!(
59
- :content_type, :description, :examples, :headers,
60
- :links, :locale, :openapi_extensions, :summary
55
+ content_keywords = keywords.slice!(*self.class.attribute_names)
56
+
57
+ # Move content-related keywords to :contents so that the first
58
+ # key-value pair in @contents is created from them.
59
+ if content_keywords.present?
60
+ content_type = content_keywords.delete(:content_type)
61
+
62
+ (keywords[:contents] ||= {}).reverse_merge!(
63
+ { content_type => content_keywords }
61
64
  )
62
- )
63
- add_example(value: keywords.delete(:example)) if keywords.key?(:example)
64
- keywords[:ref] = keywords.delete(:schema) if keywords.key?(:schema)
65
+ end
66
+ super(keywords)
67
+ end
65
68
 
66
- @schema = Schema.new(keywords)
69
+ def attribute_changed(name) # :nodoc:
70
+ @default_media_type = nil if name == :contents
71
+ super
67
72
  end
68
73
 
69
- # Returns true if content type is a JSON MIME type as specified by
70
- # https://mimesniff.spec.whatwg.org/#json-mime-type.
71
- def json_type?
72
- content_type.match?(JSON_TYPE)
74
+ def add_content(media_type = nil, keywords = {}) # :nodoc:
75
+ try_modify_attribute!(:contents) do
76
+ media_type, keywords = nil, media_type if media_type.is_a?(Hash)
77
+ media_type = Media::Type.from(media_type || Media::Type::APPLICATION_JSON)
78
+
79
+ (@contents ||= {})[media_type] = Content.new(keywords)
80
+ end
81
+ end
82
+
83
+ def default_media_type
84
+ @default_media_type ||= contents.keys.first
73
85
  end
74
86
 
75
- # Returns true if content type is <code>"application/json-seq"</code>.
76
- def json_seq_type?
77
- content_type == JSON_SEQ_TYPE
87
+ # Returns the most appropriate media type and content for the given
88
+ # media ranges.
89
+ def media_type_and_content_for(*media_ranges)
90
+ media_ranges
91
+ .filter_map { |media_range| Media::Range.try_from(media_range) }
92
+ .sort # e.g. "text/plain" before "text/*" before "*/*"
93
+ .lazy.map do |media_range|
94
+ contents.find do |media_type_and_content|
95
+ media_range =~ media_type_and_content.first
96
+ end
97
+ end.first || contents.first
78
98
  end
79
99
 
80
100
  # Returns a hash representing the \OpenAPI response object.
@@ -83,42 +103,46 @@ module Jsapi
83
103
 
84
104
  with_openapi_extensions(
85
105
  if version == OpenAPI::V2_0
106
+ media_type, content = contents.first
107
+ example = content&.examples&.values&.first
86
108
  {
87
109
  description: description,
88
- schema: schema.to_openapi(version),
89
- headers: headers.transform_values do |header|
90
- header.to_openapi(version) unless header.reference?
91
- end.compact.presence,
92
- examples: (
93
- if (example = examples.values.first).present?
94
- { content_type => example.resolve(definitions).value }
110
+ schema: content&.schema&.to_openapi(version),
111
+ headers:
112
+ headers.transform_values do |header|
113
+ header.to_openapi(version) unless header.reference?
114
+ end.compact.presence,
115
+ examples:
116
+ if media_type.present? && example.present?
117
+ { media_type => example.resolve(definitions).value }
95
118
  end
96
- )
97
119
  }
98
120
  else
99
121
  {
100
122
  summary: (summary if version >= OpenAPI::V3_2),
101
123
  description: description,
102
- headers: headers.transform_values do |header|
103
- header.to_openapi(version)
104
- end.presence,
105
- content: {
106
- content_type => {
107
- **if json_seq_type? && schema.array? && version >= OpenAPI::V3_2
108
- { itemSchema: schema.items.to_openapi(version) }
109
- else
110
- { schema: schema.to_openapi(version) }
111
- end,
112
- examples: examples.transform_values(&:to_openapi).presence
113
- }.compact
114
- },
115
- links: links.transform_values do |link|
116
- link.to_openapi(version)
117
- end.presence
124
+ headers:
125
+ headers.transform_values do |header|
126
+ header.to_openapi(version)
127
+ end.presence,
128
+ content:
129
+ contents.to_h do |nth_media_type, nth_content|
130
+ [nth_media_type, nth_content.to_openapi(version, nth_media_type)]
131
+ end.presence,
132
+ links:
133
+ links.transform_values do |link|
134
+ link.to_openapi(version)
135
+ end.presence
118
136
  }
119
137
  end
120
138
  )
121
139
  end
140
+
141
+ private
142
+
143
+ def last_content
144
+ contents.values.last || (add_content unless attributes_frozen?)
145
+ end
122
146
  end
123
147
  end
124
148
  end
@@ -4,7 +4,17 @@ module Jsapi
4
4
  module Meta
5
5
  module Response
6
6
  # Refers a reusable response.
7
- class Reference < Model::Reference; end
7
+ class Reference < Model::Reference
8
+ ##
9
+ # :attr: locale
10
+ # Overrides the locale of the referred response.
11
+ attribute :locale, Symbol
12
+
13
+ ##
14
+ # :attr: nodoc
15
+ # Prevents the reference to be described in generated \OpenAPI documents.
16
+ attribute :nodoc, values: [true, false]
17
+ end
8
18
  end
9
19
  end
10
20
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jsapi
4
+ module Meta
5
+ module Response
6
+ class Wrapper < Model::Wrapper
7
+ # The locale of the wrapped response or reference.
8
+ attr_reader :locale
9
+
10
+ def initialize(response, definitions)
11
+ @locale = response.resolve_lazily(definitions).locale
12
+ super
13
+ end
14
+
15
+ def media_type_and_content_for(*media_ranges)
16
+ super&.then do |media_type_and_content|
17
+ [
18
+ media_type_and_content.first,
19
+ Content.wrap(media_type_and_content.second, definitions)
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -2,10 +2,13 @@
2
2
 
3
3
  require_relative 'response/base'
4
4
  require_relative 'response/reference'
5
+ require_relative 'response/wrapper'
5
6
 
6
7
  module Jsapi
7
8
  module Meta
8
9
  module Response
10
+ include Model::Wrappable
11
+
9
12
  class << self
10
13
  # Creates a Base or Reference.
11
14
  def new(keywords = {})
@@ -4,6 +4,8 @@ module Jsapi
4
4
  module Meta
5
5
  module Schema
6
6
  class AdditionalProperties < Model::Base
7
+ include Model::Wrappable
8
+
7
9
  delegate_missing_to :schema
8
10
 
9
11
  ##
@@ -24,6 +26,12 @@ module Jsapi
24
26
 
25
27
  @schema = Schema.new(keywords)
26
28
  end
29
+
30
+ class Wrapper < Model::Wrapper
31
+ def schema
32
+ @schema ||= Schema.wrap(super, definitions)
33
+ end
34
+ end
27
35
  end
28
36
  end
29
37
  end
@@ -4,6 +4,12 @@ module Jsapi
4
4
  module Meta
5
5
  module Schema
6
6
  class Array < Base
7
+ class Wrapper < Schema::Wrapper
8
+ def items
9
+ @items ||= Schema.wrap(super, definitions)
10
+ end
11
+ end
12
+
7
13
  ##
8
14
  # :attr: items
9
15
  # The Schema defining the kind of items.
@@ -20,21 +26,27 @@ module Jsapi
20
26
  attribute :min_items, accessors: %i[reader]
21
27
 
22
28
  def items=(keywords = {}) # :nodoc:
23
- if keywords.key?(:schema)
24
- keywords = keywords.dup
25
- keywords[:ref] = keywords.delete(:schema)
29
+ try_modify_attribute!(:items) do
30
+ if keywords.key?(:schema)
31
+ keywords = keywords.dup
32
+ keywords[:ref] = keywords.delete(:schema)
33
+ end
34
+ @items = Schema.new(keywords)
26
35
  end
27
- @items = Schema.new(keywords)
28
36
  end
29
37
 
30
38
  def max_items=(value) # :nodoc:
31
- add_validation('max_items', Validation::MaxItems.new(value))
32
- @max_items = value
39
+ try_modify_attribute!(:max_items) do
40
+ add_validation('max_items', Validation::MaxItems.new(value))
41
+ @max_items = value
42
+ end
33
43
  end
34
44
 
35
45
  def min_items=(value) # :nodoc:
36
- add_validation('min_items', Validation::MinItems.new(value))
37
- @min_items = value
46
+ try_modify_attribute!(:min_items) do
47
+ add_validation('min_items', Validation::MinItems.new(value))
48
+ @min_items = value
49
+ end
38
50
  end
39
51
 
40
52
  def to_json_schema # :nodoc:
@@ -3,6 +3,8 @@
3
3
  module Jsapi
4
4
  module Meta
5
5
  module Schema
6
+ TYPES = %w[array boolean integer number object string].freeze # :nodoc:
7
+
6
8
  class Base < Model::Base
7
9
  include OpenAPI::Extensions
8
10
 
@@ -13,7 +15,7 @@ module Jsapi
13
15
 
14
16
  ##
15
17
  # :attr: deprecated
16
- # Specifies whether or not the schema is deprecated.
18
+ # Specifies whether the schema is marked as deprecated.
17
19
  attribute :deprecated, values: [true, false]
18
20
 
19
21
  ##
@@ -33,7 +35,7 @@ module Jsapi
33
35
 
34
36
  ##
35
37
  # :attr: external_docs
36
- # The OpenAPI::ExternalDocumentation object.
38
+ # The ExternalDocumentation object.
37
39
  attribute :external_docs, ExternalDocumentation
38
40
 
39
41
  ##
@@ -63,16 +65,15 @@ module Jsapi
63
65
  super(keywords)
64
66
  end
65
67
 
66
- # Returns the default value within +context+.
67
- def default_value(definitions = nil, context: nil)
68
- return default unless default.nil?
69
-
70
- definitions&.default_value(type, context: context)
68
+ TYPES.each do |type|
69
+ define_method(:"#{type}?") { self.type == type }
71
70
  end
72
71
 
73
72
  def enum=(value) # :nodoc:
74
- add_validation('enum', Validation::Enum.new(value))
75
- @enum = value
73
+ try_modify_attribute!(:enum) do
74
+ add_validation('enum', Validation::Enum.new(value))
75
+ @enum = value
76
+ end
76
77
  end
77
78
 
78
79
  # Returns true if and only if values can be +null+ as specified by \JSON \Schema.
@@ -4,6 +4,7 @@ module Jsapi
4
4
  module Meta
5
5
  module Schema
6
6
  class Boundary
7
+ # Transforms +value+ to an instance of this class.
7
8
  def self.from(value)
8
9
  case value
9
10
  when Boundary