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.
- checksums.yaml +4 -4
- data/lib/jsapi/controller/actions/class_methods.rb +61 -0
- data/lib/jsapi/controller/actions.rb +13 -0
- data/lib/jsapi/controller/authentication/class_methods.rb +65 -0
- data/lib/jsapi/controller/authentication/credentials/api_key.rb +24 -0
- data/lib/jsapi/controller/authentication/credentials/http/base.rb +25 -0
- data/lib/jsapi/controller/authentication/credentials/http/basic.rb +34 -0
- data/lib/jsapi/controller/authentication/credentials/http/bearer.rb +30 -0
- data/lib/jsapi/controller/authentication/credentials/http.rb +5 -0
- data/lib/jsapi/controller/authentication/credentials.rb +38 -0
- data/lib/jsapi/controller/authentication.rb +70 -0
- data/lib/jsapi/controller/base.rb +5 -4
- data/lib/jsapi/controller/methods/callbacks/callback.rb +80 -0
- data/lib/jsapi/controller/methods/callbacks/class_methods.rb +62 -0
- data/lib/jsapi/controller/methods/callbacks.rb +54 -0
- data/lib/jsapi/controller/methods.rb +209 -116
- data/lib/jsapi/controller/parameters.rb +24 -20
- data/lib/jsapi/controller/response.rb +71 -39
- data/lib/jsapi/controller.rb +2 -1
- data/lib/jsapi/dsl/base.rb +38 -5
- data/lib/jsapi/dsl/class_methods.rb +2 -2
- data/lib/jsapi/dsl/definitions.rb +41 -27
- data/lib/jsapi/dsl/operation.rb +10 -109
- data/lib/jsapi/dsl/parameter.rb +1 -1
- data/lib/jsapi/dsl/path.rb +41 -18
- data/lib/jsapi/dsl/request_body.rb +1 -1
- data/lib/jsapi/dsl/response.rb +9 -6
- data/lib/jsapi/dsl/schema.rb +11 -5
- data/lib/jsapi/dsl/shared_operation_methods.rb +140 -0
- data/lib/jsapi/dsl.rb +1 -2
- data/lib/jsapi/json/array.rb +2 -2
- data/lib/jsapi/json/object.rb +6 -6
- data/lib/jsapi/json.rb +4 -6
- data/lib/jsapi/media/range.rb +102 -0
- data/lib/jsapi/media/type.rb +70 -0
- data/lib/jsapi/media/type_and_subtype.rb +38 -0
- data/lib/jsapi/media.rb +9 -0
- data/lib/jsapi/messages.rb +19 -0
- data/lib/jsapi/meta/callback/base.rb +63 -8
- data/lib/jsapi/meta/content.rb +59 -0
- data/lib/jsapi/meta/definitions.rb +299 -153
- data/lib/jsapi/meta/example/base.rb +41 -8
- data/lib/jsapi/meta/existence.rb +4 -2
- data/lib/jsapi/meta/header/base.rb +4 -2
- data/lib/jsapi/meta/info.rb +3 -1
- data/lib/jsapi/meta/license.rb +11 -5
- data/lib/jsapi/meta/model/attributes/class_methods.rb +150 -0
- data/lib/jsapi/meta/model/attributes/frozen_error.rb +16 -0
- data/lib/jsapi/meta/model/attributes/type_caster.rb +56 -0
- data/lib/jsapi/meta/model/attributes.rb +24 -118
- data/lib/jsapi/meta/model/base.rb +2 -5
- data/lib/jsapi/meta/model/reference.rb +46 -10
- data/lib/jsapi/meta/model/wrappable.rb +23 -0
- data/lib/jsapi/meta/model/wrapper.rb +26 -0
- data/lib/jsapi/meta/model.rb +2 -1
- data/lib/jsapi/meta/oauth_flow.rb +1 -1
- data/lib/jsapi/meta/openapi/extensions.rb +5 -6
- data/lib/jsapi/meta/openapi/version.rb +16 -4
- data/lib/jsapi/meta/operation.rb +177 -71
- data/lib/jsapi/meta/parameter/base.rb +10 -6
- data/lib/jsapi/meta/parameter/wrapper.rb +13 -0
- data/lib/jsapi/meta/parameter.rb +3 -0
- data/lib/jsapi/meta/path.rb +59 -13
- data/lib/jsapi/meta/pathname.rb +6 -3
- data/lib/jsapi/meta/property.rb +10 -0
- data/lib/jsapi/meta/request_body/base.rb +69 -32
- data/lib/jsapi/meta/request_body/wrapper.rb +13 -0
- data/lib/jsapi/meta/request_body.rb +3 -0
- data/lib/jsapi/meta/rescue_handler.rb +18 -17
- data/lib/jsapi/meta/response/base.rb +82 -58
- data/lib/jsapi/meta/response/reference.rb +11 -1
- data/lib/jsapi/meta/response/wrapper.rb +26 -0
- data/lib/jsapi/meta/response.rb +3 -0
- data/lib/jsapi/meta/schema/additional_properties.rb +8 -0
- data/lib/jsapi/meta/schema/array.rb +20 -8
- data/lib/jsapi/meta/schema/base.rb +10 -9
- data/lib/jsapi/meta/schema/boundary.rb +1 -0
- data/lib/jsapi/meta/schema/numeric.rb +26 -20
- data/lib/jsapi/meta/schema/object.rb +60 -44
- data/lib/jsapi/meta/schema/reference.rb +1 -8
- data/lib/jsapi/meta/schema/string.rb +12 -6
- data/lib/jsapi/meta/schema/wrapper.rb +31 -0
- data/lib/jsapi/meta/schema.rb +22 -9
- data/lib/jsapi/meta/security_requirement.rb +2 -2
- data/lib/jsapi/meta/security_scheme/api_key.rb +5 -2
- data/lib/jsapi/meta/security_scheme/base.rb +7 -5
- data/lib/jsapi/meta/security_scheme/http/basic.rb +5 -7
- data/lib/jsapi/meta/security_scheme/http/bearer.rb +5 -5
- data/lib/jsapi/meta/security_scheme/http/other.rb +1 -3
- data/lib/jsapi/meta/security_scheme/mutual_tls.rb +1 -3
- data/lib/jsapi/meta/security_scheme/oauth2.rb +18 -13
- data/lib/jsapi/meta/security_scheme/open_id_connect.rb +4 -4
- data/lib/jsapi/meta/security_scheme.rb +4 -4
- data/lib/jsapi/meta/server.rb +4 -2
- data/lib/jsapi/meta/tag.rb +9 -3
- data/lib/jsapi/meta.rb +2 -1
- data/lib/jsapi/model/base.rb +1 -1
- data/lib/jsapi/status/base.rb +35 -0
- data/lib/jsapi/status/code.rb +113 -0
- data/lib/jsapi/status/default.rb +16 -0
- data/lib/jsapi/status/range.rb +35 -0
- data/lib/jsapi/status.rb +37 -0
- data/lib/jsapi/version.rb +1 -1
- data/lib/jsapi.rb +3 -3
- metadata +36 -10
- data/lib/jsapi/controller/parameters_invalid.rb +0 -27
- data/lib/jsapi/dsl/callback.rb +0 -21
- data/lib/jsapi/dsl/error.rb +0 -36
- data/lib/jsapi/invalid_argument_error.rb +0 -12
- data/lib/jsapi/invalid_value_error.rb +0 -12
- data/lib/jsapi/invalid_value_helper.rb +0 -17
- data/lib/jsapi/meta/model/type_caster.rb +0 -50
- 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/
|
|
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'
|
data/lib/jsapi/json/array.rb
CHANGED
|
@@ -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,
|
|
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,
|
|
10
|
+
JSON.wrap(item, schema.items, context: context)
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
data/lib/jsapi/json/object.rb
CHANGED
|
@@ -10,20 +10,20 @@ module Jsapi
|
|
|
10
10
|
|
|
11
11
|
attr_reader :raw_additional_attributes, :raw_attributes
|
|
12
12
|
|
|
13
|
-
def initialize(hash, schema,
|
|
14
|
-
schema = schema.resolve_schema(hash,
|
|
15
|
-
properties = schema.resolve_properties(
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
17
|
-
|
|
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,
|
|
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,
|
|
30
|
+
Object.new(object, schema, context: context)
|
|
33
31
|
when 'string'
|
|
34
32
|
String.new(object, schema)
|
|
35
33
|
else
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'type_and_subtype'
|
|
4
|
+
|
|
5
|
+
module Jsapi
|
|
6
|
+
module Media
|
|
7
|
+
# Represents a media range.
|
|
8
|
+
class Range
|
|
9
|
+
include Comparable
|
|
10
|
+
include TypeAndSubtype
|
|
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
|
+
|
|
18
|
+
class << self
|
|
19
|
+
# Transforms +value+ to an instance of this class.
|
|
20
|
+
#
|
|
21
|
+
# Raises an +ArgumentError+ when +value+ could not be transformed.
|
|
22
|
+
def from(value)
|
|
23
|
+
media_range = try_from(value)
|
|
24
|
+
return media_range unless media_range.nil?
|
|
25
|
+
|
|
26
|
+
raise ArgumentError, "invalid media range: #{value.inspect}"
|
|
27
|
+
end
|
|
28
|
+
|
|
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.
|
|
44
|
+
def try_from(value)
|
|
45
|
+
return value if value.is_a?(Range)
|
|
46
|
+
|
|
47
|
+
type_and_subtype = pattern.match(value.to_s)&.captures
|
|
48
|
+
new(*type_and_subtype) if type_and_subtype&.count == 2
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def pattern
|
|
54
|
+
@pattern ||= begin
|
|
55
|
+
name = '[0-9a-zA-Z-]+'
|
|
56
|
+
%r{(\*|#{name})/(\*|(?:#{name}(?:\.#{name})?(?:\+#{name})?))}.freeze
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Compares it with +other+ by +priority+.
|
|
62
|
+
def <=>(other)
|
|
63
|
+
return unless other.is_a?(self.class)
|
|
64
|
+
|
|
65
|
+
result = priority <=> other.priority
|
|
66
|
+
return result unless result.zero?
|
|
67
|
+
|
|
68
|
+
result = type <=> other.type
|
|
69
|
+
return result unless result.zero?
|
|
70
|
+
|
|
71
|
+
subtype <=> other.subtype
|
|
72
|
+
end
|
|
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
|
+
|
|
84
|
+
# Returns true if the given media type matches the media range.
|
|
85
|
+
def match?(media_type)
|
|
86
|
+
return if media_type.nil?
|
|
87
|
+
|
|
88
|
+
media_type = Type.from(media_type)
|
|
89
|
+
|
|
90
|
+
(type == '*' || type == media_type.type) &&
|
|
91
|
+
(subtype == '*' || subtype == media_type.subtype)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
alias =~ match?
|
|
95
|
+
|
|
96
|
+
# Returns the level of priority of the media range.
|
|
97
|
+
def priority
|
|
98
|
+
@priority ||= (type == '*' ? 2 : 0) + (subtype == '*' ? 1 : 0) + 1
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'type_and_subtype'
|
|
4
|
+
|
|
5
|
+
module Jsapi
|
|
6
|
+
module Media
|
|
7
|
+
# Represents a media type.
|
|
8
|
+
class Type
|
|
9
|
+
include Comparable
|
|
10
|
+
include TypeAndSubtype
|
|
11
|
+
|
|
12
|
+
# Media::Type for <code>"application/json"</code>.
|
|
13
|
+
APPLICATION_JSON = Type.new('application', 'json')
|
|
14
|
+
|
|
15
|
+
# Media::Type for <code>"application/json-seq"</code>.
|
|
16
|
+
APPLICATION_JSON_SEQ = Type.new('application', 'json-seq')
|
|
17
|
+
|
|
18
|
+
# Media::Type for <code>"text/plain"</code>.
|
|
19
|
+
TEXT_PLAIN = Type.new('text', 'plain')
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
# Transforms +value+ to an instance of this class.
|
|
23
|
+
#
|
|
24
|
+
# Raises an ArgumentError when +value+ could not be transformed.
|
|
25
|
+
def from(value)
|
|
26
|
+
media_type = try_from(value)
|
|
27
|
+
return media_type unless media_type.nil?
|
|
28
|
+
|
|
29
|
+
raise ArgumentError, "invalid media type: #{value.inspect}"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Tries to transform +value+ to an instance of this class.
|
|
33
|
+
#
|
|
34
|
+
# Returns nil if +value+ could not be transformed.
|
|
35
|
+
def try_from(value)
|
|
36
|
+
return value if value.is_a?(Type)
|
|
37
|
+
|
|
38
|
+
type_and_subtype = pattern.match(value.to_s)&.captures
|
|
39
|
+
new(*type_and_subtype) if type_and_subtype&.count == 2
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def pattern
|
|
45
|
+
@pattern ||= begin
|
|
46
|
+
name = '[0-9a-zA-Z-]+'
|
|
47
|
+
%r{(#{name})/(#{name}(?:\.#{name})?(?:\+#{name})?)}.freeze
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Compares it with +other+ by +type+ and +subtype+.
|
|
53
|
+
def <=>(other)
|
|
54
|
+
return unless other.is_a?(self.class)
|
|
55
|
+
|
|
56
|
+
result = type <=> other.type
|
|
57
|
+
return result unless result.zero?
|
|
58
|
+
|
|
59
|
+
subtype <=> other.subtype
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns true if it represents a JSON media type as specified by
|
|
63
|
+
# https://mimesniff.spec.whatwg.org/#json-mime-type.
|
|
64
|
+
def json?
|
|
65
|
+
(type.in?(%w[application text]) && subtype == 'json') ||
|
|
66
|
+
subtype.end_with?('+json')
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Media
|
|
5
|
+
module TypeAndSubtype # :nodoc:
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.attr_reader :type, :subtype
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def initialize(type, subtype)
|
|
11
|
+
@type = type.downcase
|
|
12
|
+
@subtype = subtype.downcase
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ==(other)
|
|
16
|
+
other.is_a?(self.class) &&
|
|
17
|
+
type == other.type &&
|
|
18
|
+
subtype == other.subtype
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
alias eql? ==
|
|
22
|
+
|
|
23
|
+
def hash
|
|
24
|
+
@hash ||= [type, subtype].hash
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def inspect
|
|
28
|
+
"#<#{self.class} #{to_s.inspect}>"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
@to_s ||= "#{type}/#{subtype}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
alias as_json to_s
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
data/lib/jsapi/media.rb
ADDED
|
@@ -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:
|
|
12
|
-
attribute :
|
|
64
|
+
# :attr: expressions
|
|
65
|
+
attribute :expressions, { String => Operations }, accessors: %i[reader writer]
|
|
13
66
|
|
|
14
|
-
# Adds
|
|
67
|
+
# Adds an expression.
|
|
15
68
|
#
|
|
16
69
|
# Raises an +ArgumentError+ if +expression+ is blank.
|
|
17
|
-
def
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|