jsapi 0.1.1
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 +7 -0
- data/lib/jsapi/controller/base.rb +21 -0
- data/lib/jsapi/controller/error_result.rb +21 -0
- data/lib/jsapi/controller/methods.rb +144 -0
- data/lib/jsapi/controller/parameters.rb +86 -0
- data/lib/jsapi/controller/parameters_invalid.rb +25 -0
- data/lib/jsapi/controller/response.rb +84 -0
- data/lib/jsapi/controller.rb +13 -0
- data/lib/jsapi/dsl/callbacks.rb +32 -0
- data/lib/jsapi/dsl/class_methods.rb +85 -0
- data/lib/jsapi/dsl/definitions.rb +102 -0
- data/lib/jsapi/dsl/error.rb +38 -0
- data/lib/jsapi/dsl/examples.rb +30 -0
- data/lib/jsapi/dsl/node.rb +62 -0
- data/lib/jsapi/dsl/openapi/callback.rb +23 -0
- data/lib/jsapi/dsl/openapi/root.rb +12 -0
- data/lib/jsapi/dsl/openapi.rb +4 -0
- data/lib/jsapi/dsl/operation.rb +118 -0
- data/lib/jsapi/dsl/parameter.rb +10 -0
- data/lib/jsapi/dsl/request_body.rb +10 -0
- data/lib/jsapi/dsl/response.rb +33 -0
- data/lib/jsapi/dsl/schema.rb +87 -0
- data/lib/jsapi/dsl.rb +24 -0
- data/lib/jsapi/json/array.rb +35 -0
- data/lib/jsapi/json/boolean.rb +17 -0
- data/lib/jsapi/json/integer.rb +15 -0
- data/lib/jsapi/json/null.rb +27 -0
- data/lib/jsapi/json/number.rb +15 -0
- data/lib/jsapi/json/object.rb +53 -0
- data/lib/jsapi/json/string.rb +29 -0
- data/lib/jsapi/json/value.rb +47 -0
- data/lib/jsapi/json.rb +41 -0
- data/lib/jsapi/meta/attributes/class_methods.rb +112 -0
- data/lib/jsapi/meta/attributes/type_caster.rb +48 -0
- data/lib/jsapi/meta/attributes.rb +4 -0
- data/lib/jsapi/meta/base.rb +41 -0
- data/lib/jsapi/meta/base_reference.rb +33 -0
- data/lib/jsapi/meta/definitions.rb +226 -0
- data/lib/jsapi/meta/example/model.rb +44 -0
- data/lib/jsapi/meta/example/reference.rb +15 -0
- data/lib/jsapi/meta/example.rb +19 -0
- data/lib/jsapi/meta/existence.rb +69 -0
- data/lib/jsapi/meta/invalid_argument_error.rb +11 -0
- data/lib/jsapi/meta/openapi/callback/model.rb +36 -0
- data/lib/jsapi/meta/openapi/callback/reference.rb +16 -0
- data/lib/jsapi/meta/openapi/callback.rb +21 -0
- data/lib/jsapi/meta/openapi/contact.rb +34 -0
- data/lib/jsapi/meta/openapi/external_documentation.rb +28 -0
- data/lib/jsapi/meta/openapi/info.rb +52 -0
- data/lib/jsapi/meta/openapi/license.rb +28 -0
- data/lib/jsapi/meta/openapi/link/model.rb +48 -0
- data/lib/jsapi/meta/openapi/link/reference.rb +16 -0
- data/lib/jsapi/meta/openapi/link.rb +21 -0
- data/lib/jsapi/meta/openapi/oauth_flow.rb +50 -0
- data/lib/jsapi/meta/openapi/root.rb +134 -0
- data/lib/jsapi/meta/openapi/security_requirement.rb +27 -0
- data/lib/jsapi/meta/openapi/security_scheme/api_key.rb +38 -0
- data/lib/jsapi/meta/openapi/security_scheme/base.rb +16 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/basic.rb +31 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/bearer.rb +37 -0
- data/lib/jsapi/meta/openapi/security_scheme/http/other.rb +37 -0
- data/lib/jsapi/meta/openapi/security_scheme/http.rb +31 -0
- data/lib/jsapi/meta/openapi/security_scheme/oauth2.rb +47 -0
- data/lib/jsapi/meta/openapi/security_scheme/open_id_connect.rb +33 -0
- data/lib/jsapi/meta/openapi/security_scheme.rb +51 -0
- data/lib/jsapi/meta/openapi/server.rb +34 -0
- data/lib/jsapi/meta/openapi/server_variable.rb +34 -0
- data/lib/jsapi/meta/openapi/tag.rb +34 -0
- data/lib/jsapi/meta/openapi/version.rb +41 -0
- data/lib/jsapi/meta/openapi.rb +16 -0
- data/lib/jsapi/meta/operation.rb +186 -0
- data/lib/jsapi/meta/parameter/model.rb +170 -0
- data/lib/jsapi/meta/parameter/reference.rb +30 -0
- data/lib/jsapi/meta/parameter.rb +19 -0
- data/lib/jsapi/meta/property.rb +62 -0
- data/lib/jsapi/meta/reference_error.rb +12 -0
- data/lib/jsapi/meta/request_body/model.rb +65 -0
- data/lib/jsapi/meta/request_body/reference.rb +14 -0
- data/lib/jsapi/meta/request_body.rb +19 -0
- data/lib/jsapi/meta/rescue_handler.rb +26 -0
- data/lib/jsapi/meta/response/model.rb +72 -0
- data/lib/jsapi/meta/response/reference.rb +17 -0
- data/lib/jsapi/meta/response.rb +19 -0
- data/lib/jsapi/meta/schema/array.rb +42 -0
- data/lib/jsapi/meta/schema/base.rb +146 -0
- data/lib/jsapi/meta/schema/boolean.rb +9 -0
- data/lib/jsapi/meta/schema/boundary.rb +37 -0
- data/lib/jsapi/meta/schema/conversion.rb +28 -0
- data/lib/jsapi/meta/schema/delegator.rb +26 -0
- data/lib/jsapi/meta/schema/discriminator.rb +36 -0
- data/lib/jsapi/meta/schema/integer.rb +9 -0
- data/lib/jsapi/meta/schema/number.rb +9 -0
- data/lib/jsapi/meta/schema/numeric.rb +56 -0
- data/lib/jsapi/meta/schema/object.rb +85 -0
- data/lib/jsapi/meta/schema/reference.rb +38 -0
- data/lib/jsapi/meta/schema/string.rb +58 -0
- data/lib/jsapi/meta/schema/validation/base.rb +29 -0
- data/lib/jsapi/meta/schema/validation/enum.rb +26 -0
- data/lib/jsapi/meta/schema/validation/max_items.rb +26 -0
- data/lib/jsapi/meta/schema/validation/max_length.rb +26 -0
- data/lib/jsapi/meta/schema/validation/maximum.rb +51 -0
- data/lib/jsapi/meta/schema/validation/min_items.rb +26 -0
- data/lib/jsapi/meta/schema/validation/min_length.rb +26 -0
- data/lib/jsapi/meta/schema/validation/minimum.rb +51 -0
- data/lib/jsapi/meta/schema/validation/multiple_of.rb +24 -0
- data/lib/jsapi/meta/schema/validation/pattern.rb +30 -0
- data/lib/jsapi/meta/schema/validation.rb +12 -0
- data/lib/jsapi/meta/schema.rb +61 -0
- data/lib/jsapi/meta.rb +23 -0
- data/lib/jsapi/model/attributes.rb +22 -0
- data/lib/jsapi/model/base.rb +34 -0
- data/lib/jsapi/model/error.rb +15 -0
- data/lib/jsapi/model/errors.rb +51 -0
- data/lib/jsapi/model/naming.rb +28 -0
- data/lib/jsapi/model/nestable.rb +37 -0
- data/lib/jsapi/model/nested_error.rb +54 -0
- data/lib/jsapi/model/validations.rb +27 -0
- data/lib/jsapi/model.rb +15 -0
- data/lib/jsapi/version.rb +8 -0
- data/lib/jsapi.rb +8 -0
- metadata +162 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module Attributes
|
6
|
+
module ClassMethods
|
7
|
+
# Defines an attribute.
|
8
|
+
def attribute(name, type = Object,
|
9
|
+
keys: nil,
|
10
|
+
values: nil,
|
11
|
+
default: nil,
|
12
|
+
default_key: nil,
|
13
|
+
writer: true)
|
14
|
+
|
15
|
+
(@attribute_names ||= []) << name.to_sym
|
16
|
+
|
17
|
+
instance_variable_name = "@#{name}"
|
18
|
+
|
19
|
+
# Attribute reader
|
20
|
+
define_method(name) do
|
21
|
+
value = instance_variable_get(instance_variable_name)
|
22
|
+
value.nil? ? default : value
|
23
|
+
end
|
24
|
+
|
25
|
+
case type
|
26
|
+
when Array
|
27
|
+
if writer
|
28
|
+
singular_name = name.to_s.singularize
|
29
|
+
type_caster = TypeCaster.new(type.first, values: values, name: singular_name)
|
30
|
+
|
31
|
+
# Attribute writer
|
32
|
+
define_method("#{name}=") do |argument|
|
33
|
+
instance_variable_set(
|
34
|
+
instance_variable_name,
|
35
|
+
Array.wrap(argument).map { |element| type_caster.cast(element) }
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
# add_{singular_name} method
|
40
|
+
define_method("add_#{singular_name}") do |argument = nil|
|
41
|
+
type_caster.cast(argument).tap do |casted_argument|
|
42
|
+
if instance_variable_defined?(instance_variable_name)
|
43
|
+
instance_variable_get(instance_variable_name)
|
44
|
+
else
|
45
|
+
instance_variable_set(instance_variable_name, [])
|
46
|
+
end << casted_argument
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
when Hash
|
51
|
+
singular_name = name.to_s.singularize
|
52
|
+
key_type, value_type = type.first
|
53
|
+
key_type_caster = TypeCaster.new(key_type, values: keys, name: 'key')
|
54
|
+
|
55
|
+
# hash value reader
|
56
|
+
define_method(singular_name) do |key = nil|
|
57
|
+
send(name)&.[](key_type_caster.cast(key) || default_key)
|
58
|
+
end
|
59
|
+
|
60
|
+
if writer
|
61
|
+
value_type_caster = TypeCaster.new(value_type, values: values)
|
62
|
+
|
63
|
+
# add_{singular_name} method
|
64
|
+
define_method("add_#{singular_name}") do |key_or_value, value = nil|
|
65
|
+
if value.nil? && default_key
|
66
|
+
key = default_key
|
67
|
+
value = key_or_value
|
68
|
+
else
|
69
|
+
key = key_or_value || default_key
|
70
|
+
end
|
71
|
+
raise ArgumentError, "key can't be blank" if key.blank?
|
72
|
+
|
73
|
+
casted_key = key_type_caster.cast(key)
|
74
|
+
casted_value = value_type_caster.cast(value)
|
75
|
+
|
76
|
+
if instance_variable_defined?(instance_variable_name)
|
77
|
+
instance_variable_get(instance_variable_name)
|
78
|
+
else
|
79
|
+
instance_variable_set(instance_variable_name, {})
|
80
|
+
end[casted_key] = casted_value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
else
|
84
|
+
# Predicate method
|
85
|
+
define_method("#{name}?") do
|
86
|
+
value = instance_variable_get(instance_variable_name)
|
87
|
+
value.nil? ? default || false : value
|
88
|
+
end if values == [true, false]
|
89
|
+
|
90
|
+
if writer
|
91
|
+
type_caster = TypeCaster.new(type, values: values, name: name)
|
92
|
+
|
93
|
+
# Attribute writer
|
94
|
+
define_method("#{name}=") do |argument = nil|
|
95
|
+
instance_variable_set(
|
96
|
+
instance_variable_name, type_caster.cast(argument)
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def attribute_names
|
104
|
+
names = @attribute_names || []
|
105
|
+
return names unless superclass.respond_to?(:attribute_names)
|
106
|
+
|
107
|
+
superclass.attribute_names + names
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module Attributes
|
6
|
+
class TypeCaster
|
7
|
+
STRING_CASTER = ->(arg) { arg&.to_s } # :nodoc:
|
8
|
+
|
9
|
+
SYMBOL_CASTER = ->(arg) { # :nodoc:
|
10
|
+
return if arg.nil?
|
11
|
+
|
12
|
+
arg = arg.to_s unless arg.respond_to?(:to_sym)
|
13
|
+
arg.to_sym
|
14
|
+
}
|
15
|
+
|
16
|
+
# Creates a new type caster for +klass+.
|
17
|
+
def initialize(klass, name: 'value', values: nil)
|
18
|
+
@caster =
|
19
|
+
case klass.name
|
20
|
+
when 'String'
|
21
|
+
STRING_CASTER
|
22
|
+
when 'Symbol'
|
23
|
+
SYMBOL_CASTER
|
24
|
+
else
|
25
|
+
->(arg) {
|
26
|
+
return arg if arg.is_a?(klass)
|
27
|
+
return klass.from(arg) if klass.respond_to?(:from)
|
28
|
+
return klass.new if arg.nil?
|
29
|
+
|
30
|
+
klass.new(arg)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
@values = values
|
34
|
+
@name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
# Casts +value+. Raises an InvalidArgumentError if the (casted)
|
38
|
+
# value is invalid.
|
39
|
+
def cast(value)
|
40
|
+
casted_value = @caster.call(value)
|
41
|
+
return casted_value unless @values&.exclude?(casted_value)
|
42
|
+
|
43
|
+
raise InvalidArgumentError.new(@name, casted_value, @values)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
# The base meta model class.
|
6
|
+
class Base
|
7
|
+
extend Attributes::ClassMethods
|
8
|
+
|
9
|
+
# Creates a new meta model. Raises an +ArgumentError+ if at least one
|
10
|
+
# keyword is not supported.
|
11
|
+
def initialize(keywords = {})
|
12
|
+
keywords.each do |key, value|
|
13
|
+
if respond_to?(method = "#{key}=")
|
14
|
+
public_send(method, value)
|
15
|
+
else
|
16
|
+
raise ArgumentError, "unsupported keyword: #{key}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def inspect # :nodoc:
|
22
|
+
klass = self.class
|
23
|
+
"#<#{klass.name} #{
|
24
|
+
klass.attribute_names.map do |name|
|
25
|
+
"#{name}: #{send(name).inspect}"
|
26
|
+
end.join(', ')
|
27
|
+
}>"
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns true if and only if this is a reference.
|
31
|
+
def reference?
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns itself.
|
36
|
+
def resolve(*)
|
37
|
+
self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
class BaseReference < Base
|
6
|
+
##
|
7
|
+
# :attr: ref
|
8
|
+
# The name of the referred object.
|
9
|
+
attribute :ref, String
|
10
|
+
|
11
|
+
# Returns the name of the method to be invoked to look up the referred
|
12
|
+
# object in a Definitions instance.
|
13
|
+
def self.lookup_method_name
|
14
|
+
@lookup_method_name ||=
|
15
|
+
name.delete_suffix('::Reference').demodulize.underscore
|
16
|
+
end
|
17
|
+
|
18
|
+
def reference? # :nodoc:
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
# Resolves +ref+ by looking up the object with that name in +definitions+.
|
23
|
+
#
|
24
|
+
# Raises a ReferenceError if +ref+ could not be resolved.
|
25
|
+
def resolve(definitions)
|
26
|
+
object = definitions.send(self.class.lookup_method_name, ref)
|
27
|
+
raise ReferenceError, ref if object.nil?
|
28
|
+
|
29
|
+
object.resolve(definitions)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
class Definitions
|
6
|
+
attr_reader :examples, :openapi_root, :operations, :parameters,
|
7
|
+
:request_bodies, :rescue_handlers, :responses, :schemas
|
8
|
+
|
9
|
+
def initialize(owner = nil)
|
10
|
+
@owner = owner
|
11
|
+
@examples = {}
|
12
|
+
@operations = {}
|
13
|
+
@parameters = {}
|
14
|
+
@request_bodies = {}
|
15
|
+
@responses = {}
|
16
|
+
@schemas = {}
|
17
|
+
@rescue_handlers = []
|
18
|
+
@self_and_included = [self]
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_example(name, keywords = {})
|
22
|
+
@examples[name.to_s] = Example.new(keywords)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_operation(name = nil, keywords = {})
|
26
|
+
name = name.nil? ? default_operation_name : name.to_s
|
27
|
+
@operations[name] = Operation.new(name, keywords.reverse_merge(path: default_path))
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_parameter(name, keywords = {})
|
31
|
+
name = name.to_s
|
32
|
+
@parameters[name] = Parameter.new(name, keywords)
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_request_body(name, keywords = {})
|
36
|
+
@request_bodies[name.to_s] = RequestBody.new(keywords)
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_rescue_handler(klass, status: nil)
|
40
|
+
@rescue_handlers << RescueHandler.new(klass, status: status)
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_response(name, keywords = {})
|
44
|
+
name = name.to_s
|
45
|
+
@responses[name] = Response.new(keywords)
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_schema(name, keywords = {})
|
49
|
+
name = name.to_s
|
50
|
+
@schemas[name] = Schema.new(keywords)
|
51
|
+
end
|
52
|
+
|
53
|
+
def example(name)
|
54
|
+
return unless (name = name.to_s).present?
|
55
|
+
|
56
|
+
definitions = @self_and_included.find { |d| d.examples.key?(name) }
|
57
|
+
definitions.examples[name] if definitions
|
58
|
+
end
|
59
|
+
|
60
|
+
def include(definitions)
|
61
|
+
return if @self_and_included.include?(definitions)
|
62
|
+
|
63
|
+
@self_and_included << definitions
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect # :nodoc:
|
67
|
+
"#<#{self.class.name} #{
|
68
|
+
%i[owner operations parameters request_bodies responses schemas
|
69
|
+
examples openapi_root rescue_handlers].map do |name|
|
70
|
+
"#{name}: #{instance_variable_get("@#{name}").inspect}"
|
71
|
+
end.join(', ')
|
72
|
+
}>"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns the JSON Schema document for the given schema as a +Hash+.
|
76
|
+
def json_schema_document(name)
|
77
|
+
schema(name)&.to_json_schema&.tap do |hash|
|
78
|
+
definitions =
|
79
|
+
@self_and_included
|
80
|
+
.map(&:schemas)
|
81
|
+
.reduce(&:merge)
|
82
|
+
.except(name.to_s)
|
83
|
+
.transform_values(&:to_json_schema)
|
84
|
+
|
85
|
+
hash[:definitions] = definitions if definitions.any?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a hash representing the OpenAPI document for +version+.
|
90
|
+
# Raises an +ArgumentError+ if +version+ is not supported.
|
91
|
+
def openapi_document(version = nil)
|
92
|
+
version = OpenAPI::Version.from(version)
|
93
|
+
|
94
|
+
(openapi_root&.to_openapi(version, self) || {}).tap do |h|
|
95
|
+
h[:paths] = openapi_paths(version)
|
96
|
+
|
97
|
+
if version.major == 2
|
98
|
+
h.merge!(
|
99
|
+
definitions: openapi_schemas(version),
|
100
|
+
parameters: openapi_parameters(version),
|
101
|
+
responses: openapi_responses(version)
|
102
|
+
)
|
103
|
+
else
|
104
|
+
h.deep_merge!(
|
105
|
+
components: {
|
106
|
+
schemas: openapi_schemas(version),
|
107
|
+
parameters: openapi_parameters(version),
|
108
|
+
requestBodies: openapi_request_bodies(version),
|
109
|
+
responses: openapi_responses(version),
|
110
|
+
examples: openapi_examples
|
111
|
+
}.compact.presence
|
112
|
+
)
|
113
|
+
end
|
114
|
+
end.compact
|
115
|
+
end
|
116
|
+
|
117
|
+
def openapi_root=(keywords = {})
|
118
|
+
@openapi_root = OpenAPI::Root.new(**keywords)
|
119
|
+
end
|
120
|
+
|
121
|
+
def operation(name = nil)
|
122
|
+
if (name = name.to_s).present?
|
123
|
+
definitions = @self_and_included.find { |d| d.operations.key?(name) }
|
124
|
+
definitions.operations[name] if definitions
|
125
|
+
elsif @operations.one?
|
126
|
+
# return the one and only operation
|
127
|
+
@operations.values.first
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def parameter(name)
|
132
|
+
return unless (name = name.to_s).present?
|
133
|
+
|
134
|
+
definitions = @self_and_included.find { |d| d.parameters.key?(name) }
|
135
|
+
definitions.parameters[name] if definitions
|
136
|
+
end
|
137
|
+
|
138
|
+
def request_body(name)
|
139
|
+
return unless (name = name.to_s).present?
|
140
|
+
|
141
|
+
definitions = @self_and_included.find { |d| d.request_bodies.key?(name) }
|
142
|
+
definitions.request_bodies[name] if definitions
|
143
|
+
end
|
144
|
+
|
145
|
+
def rescue_handler_for(exception)
|
146
|
+
@self_and_included.each do |definitions|
|
147
|
+
definitions.rescue_handlers.each do |rescue_handler|
|
148
|
+
return rescue_handler if rescue_handler.match?(exception)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
154
|
+
def response(name)
|
155
|
+
return unless (name = name.to_s).present?
|
156
|
+
|
157
|
+
definitions = @self_and_included.find { |d| d.responses.key?(name) }
|
158
|
+
definitions.responses[name] if definitions
|
159
|
+
end
|
160
|
+
|
161
|
+
def schema(name)
|
162
|
+
return unless (name = name.to_s).present?
|
163
|
+
|
164
|
+
definitions = @self_and_included.find { |d| d.schemas.key?(name) }
|
165
|
+
definitions.schemas[name] if definitions
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def default_operation_name
|
171
|
+
@default_operation_name ||= @owner.to_s.demodulize.delete_suffix('Controller').underscore
|
172
|
+
end
|
173
|
+
|
174
|
+
def default_path
|
175
|
+
@default_path ||= "/#{default_operation_name}"
|
176
|
+
end
|
177
|
+
|
178
|
+
def openapi_examples
|
179
|
+
@self_and_included
|
180
|
+
.map(&:examples).reduce(&:merge)
|
181
|
+
.transform_values(&:to_openapi)
|
182
|
+
.presence
|
183
|
+
end
|
184
|
+
|
185
|
+
def openapi_parameters(version)
|
186
|
+
@self_and_included
|
187
|
+
.map(&:parameters).reduce(&:merge)
|
188
|
+
.transform_values do |parameter|
|
189
|
+
parameter.to_openapi(version, self).first
|
190
|
+
end.presence
|
191
|
+
end
|
192
|
+
|
193
|
+
def openapi_paths(version)
|
194
|
+
@self_and_included
|
195
|
+
.map(&:operations).reduce(&:merge).values
|
196
|
+
.group_by { |operation| operation.path || default_path }
|
197
|
+
.transform_values do |operations|
|
198
|
+
operations.index_by(&:method).transform_values do |operation|
|
199
|
+
operation.to_openapi(version, self)
|
200
|
+
end
|
201
|
+
end.presence
|
202
|
+
end
|
203
|
+
|
204
|
+
def openapi_request_bodies(version)
|
205
|
+
@self_and_included
|
206
|
+
.map(&:request_bodies).reduce(&:merge).transform_values do |request_body|
|
207
|
+
request_body.to_openapi(version)
|
208
|
+
end.presence
|
209
|
+
end
|
210
|
+
|
211
|
+
def openapi_responses(version)
|
212
|
+
@self_and_included
|
213
|
+
.map(&:responses).reduce(&:merge).transform_values do |response|
|
214
|
+
response.to_openapi(version, self)
|
215
|
+
end.presence
|
216
|
+
end
|
217
|
+
|
218
|
+
def openapi_schemas(version)
|
219
|
+
@self_and_included
|
220
|
+
.map(&:schemas).reduce(&:merge).transform_values do |schema|
|
221
|
+
schema.to_openapi(version)
|
222
|
+
end.presence
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module Example
|
6
|
+
class Model < Base
|
7
|
+
##
|
8
|
+
# :attr: description
|
9
|
+
# The optional description of the example.
|
10
|
+
attribute :description, String
|
11
|
+
|
12
|
+
##
|
13
|
+
# :attr: external
|
14
|
+
# If true, +value+ is interpreted as a URI pointing to an external
|
15
|
+
# sample value.
|
16
|
+
attribute :external, values: [true, false]
|
17
|
+
|
18
|
+
##
|
19
|
+
# :attr: summary
|
20
|
+
# The optional summary of the example.
|
21
|
+
attribute :summary, String
|
22
|
+
|
23
|
+
##
|
24
|
+
# :attr: value
|
25
|
+
# The sample value.
|
26
|
+
attribute :value
|
27
|
+
|
28
|
+
# Returns a hash representing the \OpenAPI example object.
|
29
|
+
def to_openapi(*)
|
30
|
+
{}.tap do |hash|
|
31
|
+
hash[:summary] = summary if summary.present?
|
32
|
+
hash[:description] = description if description.present?
|
33
|
+
|
34
|
+
if external?
|
35
|
+
hash[:external_value] = value
|
36
|
+
else
|
37
|
+
hash[:value] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module Example
|
6
|
+
class Reference < BaseReference
|
7
|
+
# Returns a hash representing the \OpenAPI reference object.
|
8
|
+
def to_openapi(*)
|
9
|
+
{ '$ref': "#/components/examples/#{ref}" }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'example/model'
|
4
|
+
require_relative 'example/reference'
|
5
|
+
|
6
|
+
module Jsapi
|
7
|
+
module Meta
|
8
|
+
module Example
|
9
|
+
class << self
|
10
|
+
# Creates a new example model or reference.
|
11
|
+
def new(keywords = {})
|
12
|
+
return Reference.new(keywords) if keywords.key?(:ref)
|
13
|
+
|
14
|
+
Model.new(keywords)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
# Combines the presence concepts of the +#present?+ method and \JSON \Schema
|
6
|
+
# by four levels of existence.
|
7
|
+
class Existence
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
# The level of existence.
|
11
|
+
attr_reader :level
|
12
|
+
|
13
|
+
# Creates a new instance with the specified level.
|
14
|
+
def initialize(level)
|
15
|
+
@level = level
|
16
|
+
end
|
17
|
+
|
18
|
+
# The parameter or property can be omitted, corresponds to the opposite
|
19
|
+
# of +required+ as specified by \JSON \Schema.
|
20
|
+
ALLOW_OMITTED = new(1)
|
21
|
+
|
22
|
+
# The parameter or property value can be +nil+, corresponds to
|
23
|
+
# <code>nullable: true</code> as specified by \JSON \Schema.
|
24
|
+
ALLOW_NIL = new(2)
|
25
|
+
|
26
|
+
# The parameter or property value must respond to +nil?+ with +false+.
|
27
|
+
ALLOW_EMPTY = new(3)
|
28
|
+
|
29
|
+
# The parameter or property value must respond to +present?+ with +true+
|
30
|
+
# or must be +false+.
|
31
|
+
PRESENT = new(4)
|
32
|
+
|
33
|
+
# Creates a new instance from +value+.
|
34
|
+
def self.from(value)
|
35
|
+
return value if value.is_a?(Existence)
|
36
|
+
|
37
|
+
case value
|
38
|
+
when :present, true
|
39
|
+
PRESENT
|
40
|
+
when :allow_empty
|
41
|
+
ALLOW_EMPTY
|
42
|
+
when :allow_nil, :allow_null
|
43
|
+
ALLOW_NIL
|
44
|
+
when :allow_omitted, false, nil
|
45
|
+
ALLOW_OMITTED
|
46
|
+
else
|
47
|
+
raise ArgumentError, "invalid existence: #{value}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other) # :nodoc:
|
52
|
+
other.is_a?(Existence) && level == other.level
|
53
|
+
end
|
54
|
+
|
55
|
+
def <=>(other) # :nodoc:
|
56
|
+
level <=> other.level
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect # :nodoc:
|
60
|
+
"#<#{self.class.name} level: #{level}>"
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns true if +object+ reaches the level of existence, false otherwise.
|
64
|
+
def reach?(object)
|
65
|
+
(object.null? ? 2 : object.empty? ? 3 : 4) >= level
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module OpenAPI
|
6
|
+
module Callback
|
7
|
+
# Represents a callback object. Applies to \OpenAPI 3.x.
|
8
|
+
class Model < Base
|
9
|
+
##
|
10
|
+
# :attr: operations
|
11
|
+
attribute :operations, writer: false, default: {}
|
12
|
+
|
13
|
+
# Adds a callback operation.
|
14
|
+
#
|
15
|
+
# Raises an +ArgumentError+ if +expression+ is blank.
|
16
|
+
def add_operation(expression, keywords = {})
|
17
|
+
raise ArgumentError, "expression can't be blank" if expression.blank?
|
18
|
+
|
19
|
+
(@operations ||= {})[expression.to_s] = Operation.new(nil, keywords)
|
20
|
+
end
|
21
|
+
|
22
|
+
def operation(expression) # :nodoc:
|
23
|
+
@operations&.[](expression&.to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a hash representing the callback object.
|
27
|
+
def to_openapi(version, definitions)
|
28
|
+
operations.transform_values do |operation|
|
29
|
+
{ operation.method => operation.to_openapi(version, definitions) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jsapi
|
4
|
+
module Meta
|
5
|
+
module OpenAPI
|
6
|
+
module Callback
|
7
|
+
class Reference < BaseReference
|
8
|
+
# Returns a hash representing the \OpenAPI reference object.
|
9
|
+
def to_openapi(*)
|
10
|
+
{ '$ref': "#/components/callbacks/#{ref}" }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|