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
|
@@ -13,13 +13,18 @@ module Jsapi
|
|
|
13
13
|
attribute :description, String
|
|
14
14
|
|
|
15
15
|
##
|
|
16
|
-
# :attr:
|
|
17
|
-
#
|
|
18
|
-
attribute :
|
|
16
|
+
# :attr: external_value
|
|
17
|
+
# The URI of an external sample value.
|
|
18
|
+
attribute :external_value, String, accessors: %i[reader]
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# :attr: serialized_value
|
|
22
|
+
# The serialized form of the sample value.
|
|
23
|
+
attribute :serialized_value, accessors: %i[reader]
|
|
19
24
|
|
|
20
25
|
##
|
|
21
26
|
# :attr: summary
|
|
22
|
-
# The summary of the example.
|
|
27
|
+
# The short summary of the example.
|
|
23
28
|
attribute :summary, String
|
|
24
29
|
|
|
25
30
|
##
|
|
@@ -27,12 +32,40 @@ module Jsapi
|
|
|
27
32
|
# The sample value.
|
|
28
33
|
attribute :value
|
|
29
34
|
|
|
35
|
+
def external_value=(value) # :nodoc:
|
|
36
|
+
try_modify_attribute!(:external_value) do
|
|
37
|
+
raise 'external value and serialized value are mutually exclusive' \
|
|
38
|
+
unless serialized_value.nil?
|
|
39
|
+
|
|
40
|
+
@external_value = value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def serialized_value=(value) # :nodoc:
|
|
45
|
+
try_modify_attribute!(:serialized_value) do
|
|
46
|
+
raise 'external value and serialized value are mutually exclusive' \
|
|
47
|
+
unless external_value.nil?
|
|
48
|
+
|
|
49
|
+
@serialized_value = value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
30
53
|
# Returns a hash representing the \OpenAPI example object.
|
|
31
|
-
def to_openapi(*)
|
|
54
|
+
def to_openapi(version, *)
|
|
55
|
+
version = OpenAPI::Version.from(version)
|
|
56
|
+
|
|
32
57
|
with_openapi_extensions(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
summary: summary,
|
|
59
|
+
description: description,
|
|
60
|
+
**if version < OpenAPI::V3_2
|
|
61
|
+
{ value: value }
|
|
62
|
+
else
|
|
63
|
+
{
|
|
64
|
+
dataValue: value,
|
|
65
|
+
serializedValue: serialized_value
|
|
66
|
+
}
|
|
67
|
+
end,
|
|
68
|
+
externalValue: external_value
|
|
36
69
|
)
|
|
37
70
|
end
|
|
38
71
|
end
|
data/lib/jsapi/meta/existence.rb
CHANGED
|
@@ -30,7 +30,9 @@ module Jsapi
|
|
|
30
30
|
# or must be +false+.
|
|
31
31
|
PRESENT = new(4)
|
|
32
32
|
|
|
33
|
-
#
|
|
33
|
+
# Transforms +value+ to an instance of this class.
|
|
34
|
+
#
|
|
35
|
+
# Raises an +ArgumentError+ if +value+ could not be transformed.
|
|
34
36
|
def self.from(value)
|
|
35
37
|
return value if value.is_a?(Existence)
|
|
36
38
|
|
|
@@ -53,7 +55,7 @@ module Jsapi
|
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
def <=>(other) # :nodoc:
|
|
56
|
-
level <=> other.level
|
|
58
|
+
level <=> other.level if other.is_a?(Existence)
|
|
57
59
|
end
|
|
58
60
|
|
|
59
61
|
def inspect # :nodoc:
|
|
@@ -23,7 +23,7 @@ module Jsapi
|
|
|
23
23
|
|
|
24
24
|
##
|
|
25
25
|
# :attr: deprecated
|
|
26
|
-
# Specifies whether
|
|
26
|
+
# Specifies whether the header is marked as deprecated.
|
|
27
27
|
attribute :deprecated, values: [true, false]
|
|
28
28
|
|
|
29
29
|
##
|
|
@@ -70,7 +70,9 @@ module Jsapi
|
|
|
70
70
|
description: description,
|
|
71
71
|
deprecated: deprecated?.presence,
|
|
72
72
|
schema: schema.to_openapi(version),
|
|
73
|
-
examples: examples.transform_values
|
|
73
|
+
examples: examples.transform_values do |example|
|
|
74
|
+
example.to_openapi(version)
|
|
75
|
+
end.presence
|
|
74
76
|
}
|
|
75
77
|
end
|
|
76
78
|
)
|
data/lib/jsapi/meta/info.rb
CHANGED
data/lib/jsapi/meta/license.rb
CHANGED
|
@@ -8,7 +8,9 @@ module Jsapi
|
|
|
8
8
|
|
|
9
9
|
##
|
|
10
10
|
# :attr: identifier
|
|
11
|
-
# The SDPX identifier of the license.
|
|
11
|
+
# The SDPX identifier of the license.
|
|
12
|
+
#
|
|
13
|
+
# Applies to \OpenAPI 3.1 and higher.
|
|
12
14
|
attribute :identifier, String, accessors: %i[reader]
|
|
13
15
|
|
|
14
16
|
##
|
|
@@ -22,15 +24,19 @@ module Jsapi
|
|
|
22
24
|
attribute :url, String, accessors: %i[reader]
|
|
23
25
|
|
|
24
26
|
def identifier=(identifier) # :nodoc:
|
|
25
|
-
|
|
27
|
+
try_modify_attribute!(:identifier) do
|
|
28
|
+
raise 'identifier and url are mutually exclusive' unless url.nil?
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
@identifier = identifier
|
|
31
|
+
end
|
|
28
32
|
end
|
|
29
33
|
|
|
30
34
|
def url=(url) # :nodoc:
|
|
31
|
-
|
|
35
|
+
try_modify_attribute!(:url) do
|
|
36
|
+
raise 'identifier and url are mutually exclusive' unless identifier.nil?
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
@url = url
|
|
39
|
+
end
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
# Returns a hash representing the \OpenAPI license object.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Meta
|
|
5
|
+
module Model
|
|
6
|
+
module Attributes
|
|
7
|
+
module ClassMethods
|
|
8
|
+
DEFAULT_ARRAY = [].freeze
|
|
9
|
+
DEFAULT_HASH = {}.freeze
|
|
10
|
+
|
|
11
|
+
# Defines an attribute.
|
|
12
|
+
def attribute(name, type = Object,
|
|
13
|
+
accessors: %i[add reader writer],
|
|
14
|
+
default: nil,
|
|
15
|
+
default_key: nil,
|
|
16
|
+
keys: nil,
|
|
17
|
+
values: nil)
|
|
18
|
+
|
|
19
|
+
(@attribute_names ||= []) << name.to_sym
|
|
20
|
+
|
|
21
|
+
instance_variable_name = "@#{name}"
|
|
22
|
+
|
|
23
|
+
case type
|
|
24
|
+
when Array
|
|
25
|
+
# General default
|
|
26
|
+
default ||= DEFAULT_ARRAY
|
|
27
|
+
|
|
28
|
+
if accessors.include?(:add) || accessors.include?(:writer)
|
|
29
|
+
singular_name = name.to_s.singularize
|
|
30
|
+
add_method = "add_#{singular_name}"
|
|
31
|
+
type_caster = TypeCaster.new(type.first, values: values, name: singular_name)
|
|
32
|
+
|
|
33
|
+
# Attribute writer
|
|
34
|
+
if accessors.include?(:writer)
|
|
35
|
+
define_method("#{name}=") do |argument|
|
|
36
|
+
instance_variable_set(instance_variable_name, []).tap do
|
|
37
|
+
Array.wrap(argument).each { |element| send(add_method, element) }
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Add method
|
|
43
|
+
if accessors.include?(:add)
|
|
44
|
+
define_method(add_method) do |argument = nil|
|
|
45
|
+
try_modify_attribute!(name) do
|
|
46
|
+
type_caster.cast(argument).tap do |casted_argument|
|
|
47
|
+
if instance_variable_defined?(instance_variable_name)
|
|
48
|
+
instance_variable_get(instance_variable_name)
|
|
49
|
+
else
|
|
50
|
+
instance_variable_set(instance_variable_name, [])
|
|
51
|
+
end << casted_argument
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
when Hash
|
|
58
|
+
# General default
|
|
59
|
+
default ||= DEFAULT_HASH
|
|
60
|
+
|
|
61
|
+
singular_name = name.to_s.singularize
|
|
62
|
+
key_type, value_type = type.first
|
|
63
|
+
key_type_caster = TypeCaster.new(key_type, values: keys, name: 'key')
|
|
64
|
+
|
|
65
|
+
# Lookup method
|
|
66
|
+
if accessors.include?(:reader)
|
|
67
|
+
define_method(singular_name) do |key = nil|
|
|
68
|
+
key = default_key if key.to_s.empty?
|
|
69
|
+
send(name)[key_type_caster.cast(key)]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if accessors.include?(:add) || accessors.include?(:writer)
|
|
74
|
+
add_method = "add_#{singular_name}"
|
|
75
|
+
value_type_caster = TypeCaster.new(value_type, values: values)
|
|
76
|
+
|
|
77
|
+
# Attribute writer
|
|
78
|
+
if accessors.include?(:writer)
|
|
79
|
+
define_method("#{name}=") do |argument|
|
|
80
|
+
instance_variable_set(instance_variable_name, {}).tap do
|
|
81
|
+
Hash(argument).each { |key, value| send(add_method, key, value) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Add method
|
|
87
|
+
if accessors.include?(:add)
|
|
88
|
+
define_method(add_method) do |key_or_value, value = nil|
|
|
89
|
+
try_modify_attribute!(name) do
|
|
90
|
+
if value.nil? && default_key
|
|
91
|
+
key = default_key
|
|
92
|
+
value = key_or_value
|
|
93
|
+
else
|
|
94
|
+
key = key_or_value
|
|
95
|
+
key = default_key if key.to_s.empty?
|
|
96
|
+
end
|
|
97
|
+
raise ArgumentError, "key can't be blank" if key.to_s.empty?
|
|
98
|
+
|
|
99
|
+
if instance_variable_defined?(instance_variable_name)
|
|
100
|
+
instance_variable_get(instance_variable_name)
|
|
101
|
+
else
|
|
102
|
+
instance_variable_set(instance_variable_name, {})
|
|
103
|
+
end[key_type_caster.cast(key)] = value_type_caster.cast(value)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
# Predicate method
|
|
110
|
+
if values == [true, false] && accessors.include?(:reader)
|
|
111
|
+
define_method("#{name}?") do
|
|
112
|
+
value = instance_variable_get(instance_variable_name)
|
|
113
|
+
value.nil? ? (default == true) || false : value
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Attribute writer
|
|
118
|
+
if accessors.include?(:writer)
|
|
119
|
+
type_caster = TypeCaster.new(type, values: values, name: name)
|
|
120
|
+
|
|
121
|
+
define_method("#{name}=") do |argument = nil|
|
|
122
|
+
try_modify_attribute!(name) do
|
|
123
|
+
instance_variable_set(instance_variable_name, type_caster.cast(argument))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Attribute reader
|
|
130
|
+
if accessors.include?(:reader)
|
|
131
|
+
default = nil if default == :nil
|
|
132
|
+
|
|
133
|
+
define_method(name) do
|
|
134
|
+
value = instance_variable_get(instance_variable_name)
|
|
135
|
+
value.nil? ? default : value
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def attribute_names
|
|
141
|
+
names = @attribute_names || []
|
|
142
|
+
return names unless superclass.respond_to?(:attribute_names)
|
|
143
|
+
|
|
144
|
+
superclass.attribute_names + names
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Meta
|
|
5
|
+
module Model
|
|
6
|
+
module Attributes
|
|
7
|
+
# Raised when trying to modify a frozen attribute.
|
|
8
|
+
class FrozenError < StandardError
|
|
9
|
+
def initialize(target)
|
|
10
|
+
super("can't modify frozen #{target.class}")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Meta
|
|
5
|
+
module Model
|
|
6
|
+
module Attributes
|
|
7
|
+
class TypeCaster
|
|
8
|
+
STRING_CASTER = ->(arg) { arg&.to_s } # :nodoc:
|
|
9
|
+
|
|
10
|
+
SYMBOL_CASTER = ->(arg) { # :nodoc:
|
|
11
|
+
return if arg.nil?
|
|
12
|
+
|
|
13
|
+
arg = arg.to_s unless arg.respond_to?(:to_sym)
|
|
14
|
+
arg.to_sym
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Creates a new type caster for +klass+.
|
|
18
|
+
def initialize(klass = nil, name: 'value', values: nil)
|
|
19
|
+
klass = Object if klass.nil?
|
|
20
|
+
@caster =
|
|
21
|
+
case klass.name
|
|
22
|
+
when 'String'
|
|
23
|
+
STRING_CASTER
|
|
24
|
+
when 'Symbol'
|
|
25
|
+
SYMBOL_CASTER
|
|
26
|
+
else
|
|
27
|
+
->(arg) {
|
|
28
|
+
return arg if arg.is_a?(klass)
|
|
29
|
+
return klass.from(arg) if klass.respond_to?(:from)
|
|
30
|
+
return klass.new if arg.nil?
|
|
31
|
+
|
|
32
|
+
klass.new(arg)
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
@values = values
|
|
36
|
+
@name = name
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Casts +value+.
|
|
40
|
+
#
|
|
41
|
+
# Raises an ArgumentError if the (casted) value is invalid.
|
|
42
|
+
def cast(value)
|
|
43
|
+
casted_value = @caster.call(value)
|
|
44
|
+
return casted_value unless @values&.exclude?(casted_value)
|
|
45
|
+
|
|
46
|
+
raise ArgumentError, Messages.invalid_value(
|
|
47
|
+
name: @name,
|
|
48
|
+
value: casted_value,
|
|
49
|
+
valid_values: @values
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -1,134 +1,40 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'attributes/frozen_error'
|
|
4
|
+
require_relative 'attributes/type_caster'
|
|
5
|
+
require_relative 'attributes/class_methods'
|
|
6
|
+
|
|
3
7
|
module Jsapi
|
|
4
8
|
module Meta
|
|
5
9
|
module Model
|
|
6
10
|
module Attributes
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Defines an attribute.
|
|
11
|
-
def attribute(name, type = Object,
|
|
12
|
-
accessors: %i[add reader writer],
|
|
13
|
-
default: nil,
|
|
14
|
-
default_key: nil,
|
|
15
|
-
keys: nil,
|
|
16
|
-
values: nil)
|
|
17
|
-
|
|
18
|
-
(@attribute_names ||= []) << name.to_sym
|
|
19
|
-
|
|
20
|
-
instance_variable_name = "@#{name}"
|
|
21
|
-
|
|
22
|
-
case type
|
|
23
|
-
when Array
|
|
24
|
-
# General default
|
|
25
|
-
default ||= DEFAULT_ARRAY
|
|
26
|
-
|
|
27
|
-
if accessors.include?(:add) || accessors.include?(:writer)
|
|
28
|
-
singular_name = name.to_s.singularize
|
|
29
|
-
add_method = "add_#{singular_name}"
|
|
30
|
-
type_caster = TypeCaster.new(type.first, values: values, name: singular_name)
|
|
31
|
-
|
|
32
|
-
# Attribute writer
|
|
33
|
-
define_method("#{name}=") do |argument|
|
|
34
|
-
instance_variable_set(instance_variable_name, []).tap do
|
|
35
|
-
Array.wrap(argument).each { |element| send(add_method, element) }
|
|
36
|
-
end
|
|
37
|
-
end if accessors.include?(:writer)
|
|
38
|
-
|
|
39
|
-
# Add method
|
|
40
|
-
define_method(add_method) 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
|
-
attribute_changed(name)
|
|
48
|
-
end
|
|
49
|
-
end if accessors.include?(:add)
|
|
50
|
-
end
|
|
51
|
-
when Hash
|
|
52
|
-
# General default
|
|
53
|
-
default ||= DEFAULT_HASH
|
|
54
|
-
|
|
55
|
-
singular_name = name.to_s.singularize
|
|
56
|
-
key_type, value_type = type.first
|
|
57
|
-
key_type_caster = TypeCaster.new(key_type, values: keys, name: 'key')
|
|
58
|
-
|
|
59
|
-
# Lookup method
|
|
60
|
-
define_method(singular_name) do |key = nil|
|
|
61
|
-
key = default_key if key.to_s.empty?
|
|
62
|
-
send(name)[key_type_caster.cast(key)]
|
|
63
|
-
end if accessors.include?(:reader)
|
|
64
|
-
|
|
65
|
-
if accessors.include?(:add) || accessors.include?(:writer)
|
|
66
|
-
add_method = "add_#{singular_name}"
|
|
67
|
-
value_type_caster = TypeCaster.new(value_type, values: values)
|
|
68
|
-
|
|
69
|
-
# Attribute writer
|
|
70
|
-
define_method("#{name}=") do |argument|
|
|
71
|
-
instance_variable_set(instance_variable_name, {}).tap do
|
|
72
|
-
Hash(argument).each { |key, value| send(add_method, key, value) }
|
|
73
|
-
end
|
|
74
|
-
end if accessors.include?(:writer)
|
|
75
|
-
|
|
76
|
-
# Add method
|
|
77
|
-
define_method(add_method) do |key_or_value, value = nil|
|
|
78
|
-
if value.nil? && default_key
|
|
79
|
-
key = default_key
|
|
80
|
-
value = key_or_value
|
|
81
|
-
else
|
|
82
|
-
key = key_or_value
|
|
83
|
-
key = default_key if key.to_s.empty?
|
|
84
|
-
end
|
|
85
|
-
raise ArgumentError, "key can't be blank" if key.to_s.empty?
|
|
86
|
-
|
|
87
|
-
casted_key = key_type_caster.cast(key)
|
|
88
|
-
casted_value = value_type_caster.cast(value)
|
|
11
|
+
def self.included(base) # :nodoc:
|
|
12
|
+
base.extend(ClassMethods)
|
|
13
|
+
end
|
|
89
14
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
end[casted_key] = casted_value
|
|
15
|
+
# Returns true when attributes are frozen.
|
|
16
|
+
def attributes_frozen?
|
|
17
|
+
@attributes_frozen == true
|
|
18
|
+
end
|
|
95
19
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else
|
|
101
|
-
# Predicate method
|
|
102
|
-
define_method("#{name}?") do
|
|
103
|
-
value = instance_variable_get(instance_variable_name)
|
|
104
|
-
value.nil? ? default || false : value
|
|
105
|
-
end if values == [true, false] && accessors.include?(:reader)
|
|
20
|
+
# Freezes attributes.
|
|
21
|
+
def freeze_attributes
|
|
22
|
+
@attributes_frozen = true
|
|
23
|
+
end
|
|
106
24
|
|
|
107
|
-
|
|
108
|
-
type_caster = TypeCaster.new(type, values: values, name: name)
|
|
25
|
+
protected
|
|
109
26
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
type_caster.cast(argument).tap do |casted_value|
|
|
113
|
-
instance_variable_set(instance_variable_name, casted_value)
|
|
114
|
-
attribute_changed(name)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
end
|
|
27
|
+
# Invoked whenever an attribute has been changed.
|
|
28
|
+
def attribute_changed(name); end
|
|
119
29
|
|
|
120
|
-
|
|
121
|
-
define_method(name) do
|
|
122
|
-
value = instance_variable_get(instance_variable_name)
|
|
123
|
-
value.nil? ? default : value
|
|
124
|
-
end if accessors.include?(:reader)
|
|
125
|
-
end
|
|
30
|
+
private
|
|
126
31
|
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
return names unless superclass.respond_to?(:attribute_names)
|
|
32
|
+
def try_modify_attribute!(name)
|
|
33
|
+
raise FrozenError.new(self) if attributes_frozen?
|
|
130
34
|
|
|
131
|
-
|
|
35
|
+
result = yield if block_given?
|
|
36
|
+
attribute_changed(name)
|
|
37
|
+
result
|
|
132
38
|
end
|
|
133
39
|
end
|
|
134
40
|
end
|
|
@@ -5,7 +5,7 @@ module Jsapi
|
|
|
5
5
|
module Model
|
|
6
6
|
# The base meta model class.
|
|
7
7
|
class Base
|
|
8
|
-
|
|
8
|
+
include Attributes
|
|
9
9
|
|
|
10
10
|
# Creates a new meta model.
|
|
11
11
|
#
|
|
@@ -48,10 +48,7 @@ module Jsapi
|
|
|
48
48
|
self
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# Invoked whenever an attribute has been changed.
|
|
54
|
-
def attribute_changed(name); end
|
|
51
|
+
alias resolve_lazily resolve
|
|
55
52
|
end
|
|
56
53
|
end
|
|
57
54
|
end
|
|
@@ -5,19 +5,47 @@ module Jsapi
|
|
|
5
5
|
module Model
|
|
6
6
|
# The base reference class.
|
|
7
7
|
class Reference < Base
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
class Resolver # :nodoc:
|
|
9
|
+
def initialize(reference, definitions)
|
|
10
|
+
@reference = reference
|
|
11
|
+
@definitions = definitions
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
protected
|
|
15
|
+
|
|
16
|
+
def respond_to_missing?(...)
|
|
17
|
+
@reference.respond_to?(...)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def method_missing(name, ...)
|
|
23
|
+
result = @reference.send(name, ...)
|
|
24
|
+
return result unless result.nil?
|
|
25
|
+
|
|
26
|
+
@reference
|
|
27
|
+
.resolve(@definitions, deep: false)
|
|
28
|
+
.resolve_lazily(@definitions)
|
|
29
|
+
.send(name, ...)
|
|
30
|
+
end
|
|
11
31
|
end
|
|
12
32
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
33
|
+
class << self
|
|
34
|
+
# Derrives the component type from the inner most module name.
|
|
35
|
+
def component_type
|
|
36
|
+
@component_type ||= name.split('::')[-2].underscore
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Derrives the \OpenAPI component type from the inner most module name.
|
|
40
|
+
def openapi_component_type
|
|
41
|
+
@openapi_component_type ||= name.split('::')[-2].pluralize.camelize(:lower)
|
|
42
|
+
end
|
|
16
43
|
end
|
|
17
44
|
|
|
18
45
|
##
|
|
19
46
|
# :attr: description
|
|
20
47
|
# The description to be displayed instead of the description of the referred object.
|
|
48
|
+
#
|
|
21
49
|
# Applies to \OpenAPI 3.1 and higher.
|
|
22
50
|
attribute :description, String
|
|
23
51
|
|
|
@@ -29,6 +57,7 @@ module Jsapi
|
|
|
29
57
|
##
|
|
30
58
|
# :attr: summary
|
|
31
59
|
# The summary to be displayed instead of the summary of the referred object.
|
|
60
|
+
#
|
|
32
61
|
# Applies to \OpenAPI 3.1 and higher.
|
|
33
62
|
attribute :summary, String
|
|
34
63
|
|
|
@@ -37,14 +66,21 @@ module Jsapi
|
|
|
37
66
|
true
|
|
38
67
|
end
|
|
39
68
|
|
|
40
|
-
# Resolves
|
|
69
|
+
# Resolves the reference by looking up the referred object in +definitions+.
|
|
41
70
|
#
|
|
42
|
-
# Raises a ReferenceError if
|
|
43
|
-
def resolve(definitions)
|
|
71
|
+
# Raises a ReferenceError if the reference could not be resolved.
|
|
72
|
+
def resolve(definitions, deep: true)
|
|
44
73
|
object = definitions.send("find_#{self.class.component_type}", ref)
|
|
45
74
|
raise ReferenceError, ref if object.nil?
|
|
46
75
|
|
|
47
|
-
object.resolve(definitions)
|
|
76
|
+
deep ? object.resolve(definitions, deep: true) : object
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Lazily resolves the reference.
|
|
80
|
+
#
|
|
81
|
+
# Raises a ReferenceError if the reference could not be resolved.
|
|
82
|
+
def resolve_lazily(definitions)
|
|
83
|
+
Resolver.new(self, definitions)
|
|
48
84
|
end
|
|
49
85
|
|
|
50
86
|
# Returns a hash representing the \OpenAPI reference object.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jsapi
|
|
4
|
+
module Meta
|
|
5
|
+
module Model
|
|
6
|
+
# Defines a +wrap+ class method to wrap an instance of the given class.
|
|
7
|
+
module Wrappable
|
|
8
|
+
def self.included(base) # :nodoc:
|
|
9
|
+
class << base
|
|
10
|
+
define_method(:wrap) do |model, definitions|
|
|
11
|
+
return if model.nil?
|
|
12
|
+
|
|
13
|
+
wrapper_class = "#{name}::Wrapper".constantize
|
|
14
|
+
return model if model.is_a?(wrapper_class)
|
|
15
|
+
|
|
16
|
+
wrapper_class.new(model, definitions)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|