explicit 0.2.0 → 0.2.2
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/README.md +76 -68
- data/app/helpers/explicit/application_helper.rb +32 -0
- data/app/views/explicit/documentation/_attribute.html.erb +38 -0
- data/app/views/explicit/documentation/_page.html.erb +166 -0
- data/app/views/explicit/documentation/_request.html.erb +87 -0
- data/app/views/explicit/documentation/request/_examples.html.erb +50 -0
- data/app/views/explicit/documentation/type/_agreement.html.erb +7 -0
- data/app/views/explicit/documentation/type/_array.html.erb +3 -0
- data/app/views/explicit/documentation/type/_big_decimal.html.erb +4 -0
- data/app/views/explicit/documentation/type/_boolean.html.erb +7 -0
- data/app/views/explicit/documentation/type/_date_time_iso8601.html.erb +3 -0
- data/app/views/explicit/documentation/type/_date_time_posix.html.erb +3 -0
- data/app/views/explicit/documentation/type/_enum.html.erb +7 -0
- data/app/views/explicit/documentation/type/_file.html.erb +9 -0
- data/app/views/explicit/documentation/type/_hash.html.erb +4 -0
- data/app/views/explicit/documentation/type/_integer.html.erb +25 -0
- data/app/views/explicit/documentation/type/_one_of.html.erb +11 -0
- data/app/views/explicit/documentation/type/_record.html.erb +9 -0
- data/app/views/explicit/documentation/type/_string.html.erb +21 -0
- data/config/locales/en.yml +27 -11
- data/lib/explicit/configuration.rb +1 -1
- data/lib/explicit/documentation/builder.rb +80 -0
- data/lib/explicit/documentation/markdown.rb +2 -13
- data/lib/explicit/documentation/output/swagger.rb +176 -0
- data/lib/explicit/documentation/output/webpage.rb +31 -0
- data/lib/explicit/documentation/page/partial.rb +20 -0
- data/lib/explicit/documentation/page/request.rb +27 -0
- data/lib/explicit/documentation/section.rb +9 -0
- data/lib/explicit/documentation.rb +12 -145
- data/lib/explicit/request/example.rb +50 -1
- data/lib/explicit/request/invalid_params_error.rb +1 -3
- data/lib/explicit/request/invalid_response_error.rb +2 -15
- data/lib/explicit/request/route.rb +18 -0
- data/lib/explicit/request.rb +43 -24
- data/lib/explicit/test_helper/example_recorder.rb +7 -2
- data/lib/explicit/test_helper.rb +25 -7
- data/lib/explicit/type/agreement.rb +39 -0
- data/lib/explicit/type/array.rb +56 -0
- data/lib/explicit/type/big_decimal.rb +58 -0
- data/lib/explicit/type/boolean.rb +47 -0
- data/lib/explicit/type/date_time_iso8601.rb +41 -0
- data/lib/explicit/type/date_time_posix.rb +44 -0
- data/lib/explicit/type/enum.rb +41 -0
- data/lib/explicit/type/file.rb +60 -0
- data/lib/explicit/type/hash.rb +57 -0
- data/lib/explicit/type/integer.rb +79 -0
- data/lib/explicit/type/literal.rb +45 -0
- data/lib/explicit/type/modifiers/default.rb +24 -0
- data/lib/explicit/type/modifiers/description.rb +11 -0
- data/lib/explicit/type/modifiers/nilable.rb +19 -0
- data/lib/explicit/type/modifiers/param_location.rb +11 -0
- data/lib/explicit/type/one_of.rb +46 -0
- data/lib/explicit/type/record.rb +96 -0
- data/lib/explicit/type/string.rb +68 -0
- data/lib/explicit/type.rb +112 -0
- data/lib/explicit/version.rb +1 -1
- data/lib/explicit.rb +28 -18
- metadata +47 -25
- data/app/views/explicit/application/_documentation.html.erb +0 -136
- data/app/views/explicit/application/_request.html.erb +0 -37
- data/lib/explicit/documentation/property.rb +0 -19
- data/lib/explicit/spec/agreement.rb +0 -17
- data/lib/explicit/spec/array.rb +0 -28
- data/lib/explicit/spec/bigdecimal.rb +0 -27
- data/lib/explicit/spec/boolean.rb +0 -30
- data/lib/explicit/spec/date_time_iso8601.rb +0 -17
- data/lib/explicit/spec/date_time_posix.rb +0 -21
- data/lib/explicit/spec/default.rb +0 -20
- data/lib/explicit/spec/error.rb +0 -63
- data/lib/explicit/spec/hash.rb +0 -30
- data/lib/explicit/spec/inclusion.rb +0 -15
- data/lib/explicit/spec/integer.rb +0 -53
- data/lib/explicit/spec/literal.rb +0 -15
- data/lib/explicit/spec/nilable.rb +0 -15
- data/lib/explicit/spec/one_of.rb +0 -40
- data/lib/explicit/spec/record.rb +0 -33
- data/lib/explicit/spec/string.rb +0 -50
- data/lib/explicit/spec.rb +0 -72
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::BigDecimal < Explicit::Type
|
|
4
|
+
attr_reader :min, :max
|
|
5
|
+
|
|
6
|
+
def initialize(min: nil, max: nil)
|
|
7
|
+
@min = min
|
|
8
|
+
@max = max
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def validate(value)
|
|
12
|
+
unless value.is_a?(::String) || value.is_a?(::Integer)
|
|
13
|
+
return [:error, error_i18n("bigdecimal")]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
decimalvalue = BigDecimal(value)
|
|
17
|
+
|
|
18
|
+
if min && decimalvalue < min
|
|
19
|
+
return [:error, error_i18n("min", min:)]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
if max && decimalvalue > max
|
|
23
|
+
return [:error, error_i18n("max", max:)]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
[:ok, decimalvalue]
|
|
27
|
+
rescue ArgumentError
|
|
28
|
+
return [:error, error_i18n("bigdecimal")]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
concerning :Webpage do
|
|
32
|
+
def summary
|
|
33
|
+
"string"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def partial
|
|
37
|
+
"explicit/documentation/type/big_decimal"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def has_details?
|
|
41
|
+
true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
concerning :Swagger do
|
|
46
|
+
def swagger_schema
|
|
47
|
+
{
|
|
48
|
+
type: "string",
|
|
49
|
+
pattern: /^\d*\.?\d*$/.inspect,
|
|
50
|
+
format: "decimal number",
|
|
51
|
+
description: swagger_description([
|
|
52
|
+
min&.then { swagger_i18n("big_decimal_min", min: _1) },
|
|
53
|
+
max&.then { swagger_i18n("big_decimal_max", max: _1) }
|
|
54
|
+
])
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Boolean < Explicit::Type
|
|
4
|
+
VALUES = {
|
|
5
|
+
true => true,
|
|
6
|
+
"true" => true,
|
|
7
|
+
"on" => true,
|
|
8
|
+
"1" => true,
|
|
9
|
+
1 => true,
|
|
10
|
+
false => false,
|
|
11
|
+
"false" => false,
|
|
12
|
+
"off" => false,
|
|
13
|
+
"0" => false,
|
|
14
|
+
0 => false
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def validate(value)
|
|
18
|
+
value = VALUES[value]
|
|
19
|
+
|
|
20
|
+
return [:error, error_i18n("boolean")] if value.nil?
|
|
21
|
+
|
|
22
|
+
[:ok, value]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
concerning :Webpage do
|
|
26
|
+
def summary
|
|
27
|
+
"boolean"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def partial
|
|
31
|
+
"explicit/documentation/type/boolean"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def has_details?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
concerning :Swagger do
|
|
40
|
+
def swagger_schema
|
|
41
|
+
{
|
|
42
|
+
type: "boolean",
|
|
43
|
+
description: swagger_description([])
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
class Explicit::Type::DateTimeISO8601 < Explicit::Type
|
|
6
|
+
def validate(value)
|
|
7
|
+
return [:error, error_i18n("date_time_iso8601")] if !value.is_a?(::String)
|
|
8
|
+
|
|
9
|
+
timeval = Time.iso8601(value)
|
|
10
|
+
|
|
11
|
+
[:ok, timeval]
|
|
12
|
+
rescue ArgumentError
|
|
13
|
+
[:error, error_i18n("date_time_iso8601")]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
concerning :Webpage do
|
|
17
|
+
def summary
|
|
18
|
+
"string"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def partial
|
|
22
|
+
"explicit/documentation/type/date_time_iso8601"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def has_details?
|
|
26
|
+
true
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
concerning :Swagger do
|
|
31
|
+
def swagger_schema
|
|
32
|
+
{
|
|
33
|
+
type: "string",
|
|
34
|
+
format: "date-time",
|
|
35
|
+
description: swagger_description([
|
|
36
|
+
swagger_i18n("date_time_iso8601")
|
|
37
|
+
])
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "time"
|
|
4
|
+
|
|
5
|
+
class Explicit::Type::DateTimePosix < Explicit::Type
|
|
6
|
+
def validate(value)
|
|
7
|
+
if !value.is_a?(::Integer) && !value.is_a?(::String)
|
|
8
|
+
return [:error, error_i18n("date_time_posix")]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
datetimeval = DateTime.strptime(value.to_s, "%s")
|
|
12
|
+
|
|
13
|
+
[:ok, datetimeval]
|
|
14
|
+
rescue Date::Error
|
|
15
|
+
return [:error, error_i18n("date_time_posix")]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
concerning :Webpage do
|
|
19
|
+
def summary
|
|
20
|
+
"integer"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def partial
|
|
24
|
+
"explicit/documentation/type/date_time_posix"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def has_details?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
concerning :Swagger do
|
|
33
|
+
def swagger_schema
|
|
34
|
+
{
|
|
35
|
+
type: "integer",
|
|
36
|
+
minimum: 1,
|
|
37
|
+
format: "POSIX time",
|
|
38
|
+
description: swagger_description([
|
|
39
|
+
swagger_i18n("date_time_posix")
|
|
40
|
+
])
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Enum < Explicit::Type
|
|
4
|
+
attr_reader :allowed_values
|
|
5
|
+
|
|
6
|
+
def initialize(allowed_values)
|
|
7
|
+
@allowed_values = allowed_values
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate(value)
|
|
11
|
+
if allowed_values.include?(value)
|
|
12
|
+
[:ok, value]
|
|
13
|
+
else
|
|
14
|
+
[:error, error_i18n("enum", allowed_values: allowed_values.inspect)]
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
concerning :Webpage do
|
|
19
|
+
def summary
|
|
20
|
+
"string"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def partial
|
|
24
|
+
"explicit/documentation/type/enum"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def has_details?
|
|
28
|
+
true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
concerning :Swagger do
|
|
33
|
+
def swagger_schema
|
|
34
|
+
{
|
|
35
|
+
type: "string",
|
|
36
|
+
enum: allowed_values,
|
|
37
|
+
description: swagger_description([])
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::File < Explicit::Type
|
|
4
|
+
include ActionView::Helpers::NumberHelper
|
|
5
|
+
|
|
6
|
+
attr_reader :max_size, :content_types
|
|
7
|
+
|
|
8
|
+
FILE_CLASSES = [
|
|
9
|
+
ActionDispatch::Http::UploadedFile,
|
|
10
|
+
Rack::Test::UploadedFile
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
def initialize(max_size: nil, content_types: nil)
|
|
14
|
+
@max_size = max_size
|
|
15
|
+
@content_types = Array(content_types)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate(value)
|
|
19
|
+
if !FILE_CLASSES.any? { |klass| value.is_a?(klass) }
|
|
20
|
+
return [:error, error_i18n("file")]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if max_size && value.size > max_size
|
|
24
|
+
return [:error, error_i18n("file_max_size", max_size: number_to_human_size(max_size))]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
if content_types.any? && !content_types.include?(value.content_type)
|
|
28
|
+
return [:error, error_i18n("file_content_type", allowed_content_types: content_types.inspect)]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
[:ok, value]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
concerning :Webpage do
|
|
35
|
+
def summary
|
|
36
|
+
"file"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def partial
|
|
40
|
+
"explicit/documentation/type/file"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def has_details?
|
|
44
|
+
max_size.present? || content_types.any?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
concerning :Swagger do
|
|
49
|
+
def swagger_schema
|
|
50
|
+
{
|
|
51
|
+
type: "string",
|
|
52
|
+
format: "binary",
|
|
53
|
+
description: swagger_description([
|
|
54
|
+
max_size&.then { swagger_i18n("file_max_size", max_size: number_to_human_size(_1)) },
|
|
55
|
+
content_types.any? ? swagger_i18n("file_content_types", content_types: content_types.join(', ')) : nil
|
|
56
|
+
])
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Hash < Explicit::Type
|
|
4
|
+
attr_reader :keytype, :valuetype, :empty
|
|
5
|
+
|
|
6
|
+
def initialize(keytype:, valuetype:, empty: true)
|
|
7
|
+
@keytype = Explicit::Type.build(keytype)
|
|
8
|
+
@valuetype = Explicit::Type.build(valuetype)
|
|
9
|
+
@empty = empty
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def validate(value)
|
|
13
|
+
return [:error, error_i18n("hash")] if !value.respond_to?(:[])
|
|
14
|
+
return [:error, error_i18n("empty")] if value.empty? && empty == false
|
|
15
|
+
|
|
16
|
+
validated_hash = {}
|
|
17
|
+
|
|
18
|
+
value.each do |key, value|
|
|
19
|
+
case [keytype.validate(key), valuetype.validate(value)]
|
|
20
|
+
in [[:ok, validated_key], [:ok, validated_value]]
|
|
21
|
+
validated_hash[validated_key] = validated_value
|
|
22
|
+
in [[:error, error], _]
|
|
23
|
+
return [:error, error_i18n("hash_key", key:, error:)]
|
|
24
|
+
in [_, [:error, error]]
|
|
25
|
+
return [:error, error_i18n("hash_value", key:, error:)]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
[:ok, validated_hash]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
concerning :Webpage do
|
|
33
|
+
def summary
|
|
34
|
+
"object"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def partial
|
|
38
|
+
"explicit/documentation/type/hash"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def has_details?
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
concerning :Swagger do
|
|
47
|
+
def swagger_schema
|
|
48
|
+
{
|
|
49
|
+
type: "object",
|
|
50
|
+
additionalProperties: valuetype.swagger_schema,
|
|
51
|
+
description: swagger_description([
|
|
52
|
+
empty == false ? swagger_i18n("hash_not_empty") : nil
|
|
53
|
+
])
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Integer < Explicit::Type
|
|
4
|
+
attr_reader :min, :max, :negative, :positive
|
|
5
|
+
|
|
6
|
+
def initialize(min: nil, max: nil, negative: nil, positive: nil)
|
|
7
|
+
@min = min
|
|
8
|
+
@max = max
|
|
9
|
+
@negative = negative
|
|
10
|
+
@positive = positive
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
ParseFromString = ->(value) do
|
|
14
|
+
Integer(value)
|
|
15
|
+
rescue ::ArgumentError
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def validate(value)
|
|
20
|
+
value =
|
|
21
|
+
if value.is_a?(::Integer)
|
|
22
|
+
value
|
|
23
|
+
elsif value.is_a?(::String)
|
|
24
|
+
ParseFromString[value]
|
|
25
|
+
else
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
return [:error, error_i18n("integer")] if value.nil?
|
|
30
|
+
|
|
31
|
+
if min && value < min
|
|
32
|
+
return [:error, error_i18n("min", min:)]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if max && value > max
|
|
36
|
+
return [:error, error_i18n("max", max:)]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if negative == false && value < 0
|
|
40
|
+
return [:error, error_i18n("not_negative")]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if positive == false && value > 0
|
|
44
|
+
return [:error, error_i18n("not_positive")]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
[:ok, value]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
concerning :Webpage do
|
|
51
|
+
def summary
|
|
52
|
+
"integer"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def partial
|
|
56
|
+
"explicit/documentation/type/integer"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def has_details?
|
|
60
|
+
min.present? || max.present? || !negative.nil? || !positive.nil?
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
concerning :Swagger do
|
|
65
|
+
def swagger_schema
|
|
66
|
+
{
|
|
67
|
+
type: "integer",
|
|
68
|
+
minimum: min,
|
|
69
|
+
maximum: max,
|
|
70
|
+
description: swagger_description([
|
|
71
|
+
positive == false ? swagger_i18n("integer_not_positive") : nil,
|
|
72
|
+
positive == true ? swagger_i18n("integer_only_positive") : nil,
|
|
73
|
+
negative == false ? swagger_i18n("integer_not_negative") : nil,
|
|
74
|
+
negative == true ? swagger_i18n("integer_only_negative") : nil
|
|
75
|
+
])
|
|
76
|
+
}.compact_blank
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Literal < Explicit::Type
|
|
4
|
+
attr_reader :value
|
|
5
|
+
|
|
6
|
+
def initialize(value:)
|
|
7
|
+
if !value.is_a?(::String) && !value.is_a?(::Integer)
|
|
8
|
+
raise ArgumentError("literal must be a string or integer")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
@value = value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def validate(value)
|
|
15
|
+
if value == @value
|
|
16
|
+
[:ok, value]
|
|
17
|
+
else
|
|
18
|
+
[:error, error_i18n("literal", value: @value.inspect)]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
concerning :Webpage do
|
|
23
|
+
def summary
|
|
24
|
+
@value.inspect
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def partial
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def has_details?
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
concerning :Swagger do
|
|
37
|
+
def swagger_schema
|
|
38
|
+
{
|
|
39
|
+
type: @value.is_a?(::String) ? "string" : "integer",
|
|
40
|
+
enum: [@value],
|
|
41
|
+
description: swagger_description([])
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Explicit::Type::Modifiers::Default
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def apply(default, type)
|
|
7
|
+
Explicit::Type.build(type).tap do |type|
|
|
8
|
+
type.default = default if type.is_a?(Explicit::Type) # TODO: remove check
|
|
9
|
+
|
|
10
|
+
original_validate = type.method(:validate)
|
|
11
|
+
|
|
12
|
+
type.define_singleton_method(:validate, lambda do |value|
|
|
13
|
+
value =
|
|
14
|
+
if value.nil?
|
|
15
|
+
default.respond_to?(:call) ? default.call : default
|
|
16
|
+
else
|
|
17
|
+
value
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
original_validate.(value)
|
|
21
|
+
end)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Explicit::Type::Modifiers::Description
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def apply(description, type)
|
|
7
|
+
Explicit::Type.build(type).tap do |type|
|
|
8
|
+
type.description = description if type.is_a?(Explicit::Type) # TODO: remove check
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Explicit::Type::Modifiers::Nilable
|
|
4
|
+
extend self
|
|
5
|
+
|
|
6
|
+
def apply(type)
|
|
7
|
+
Explicit::Type.build(type).tap do |type|
|
|
8
|
+
type.nilable = true if type.is_a?(Explicit::Type) # TODO: remove check
|
|
9
|
+
|
|
10
|
+
original_validate = type.method(:validate)
|
|
11
|
+
|
|
12
|
+
type.define_singleton_method(:validate, lambda do |value|
|
|
13
|
+
return [:ok, nil] if value.nil?
|
|
14
|
+
|
|
15
|
+
original_validate.(value)
|
|
16
|
+
end)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::OneOf < Explicit::Type
|
|
4
|
+
attr_reader :subtypes
|
|
5
|
+
|
|
6
|
+
def initialize(subtypes:)
|
|
7
|
+
@subtypes = subtypes.map { Explicit::Type.build(_1) }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def validate(value)
|
|
11
|
+
errors = []
|
|
12
|
+
|
|
13
|
+
@subtypes.each do |subtype|
|
|
14
|
+
case subtype.validate(value)
|
|
15
|
+
in [:ok, validated_value]
|
|
16
|
+
return [:ok, validated_value]
|
|
17
|
+
in [:error, err]
|
|
18
|
+
errors << err
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
[:error, errors.join(" OR ")]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
concerning :Webpage do
|
|
26
|
+
def summary
|
|
27
|
+
@subtypes.all? { _1.is_a?(Explicit::Type::Record) } ? "object" : "any"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def partial
|
|
31
|
+
"explicit/documentation/type/one_of"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def has_details?
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
concerning :Swagger do
|
|
40
|
+
def swagger_schema
|
|
41
|
+
return subtypes.first.swagger_schema if subtypes.one?
|
|
42
|
+
|
|
43
|
+
{ oneOf: subtypes.map(&:swagger_schema) }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Explicit::Type::Record < Explicit::Type
|
|
4
|
+
attr_reader :attributes
|
|
5
|
+
|
|
6
|
+
def initialize(attributes:)
|
|
7
|
+
@attributes = attributes.map do |attribute_name, type|
|
|
8
|
+
type = Explicit::Type.build(type) if !type.is_a?(Explicit::Type)
|
|
9
|
+
|
|
10
|
+
[attribute_name, type]
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def validate(data)
|
|
15
|
+
return [:error, error_i18n("hash")] if !data.respond_to?(:[])
|
|
16
|
+
|
|
17
|
+
validated_data = {}
|
|
18
|
+
errors = {}
|
|
19
|
+
|
|
20
|
+
@attributes.each do |attribute_name, type|
|
|
21
|
+
value = data[attribute_name]
|
|
22
|
+
|
|
23
|
+
case type.validate(value)
|
|
24
|
+
in [:ok, validated_value]
|
|
25
|
+
validated_data[attribute_name] = validated_value
|
|
26
|
+
in [:error, err]
|
|
27
|
+
errors[attribute_name] = err
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
return [:error, errors] if errors.any?
|
|
32
|
+
|
|
33
|
+
[:ok, validated_data]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def path_params_type
|
|
37
|
+
path_params = @attributes.filter do |name, type|
|
|
38
|
+
type.param_location_path?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
self.class.new(attributes: path_params)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def body_params_type
|
|
45
|
+
body_params = @attributes.filter do |name, type|
|
|
46
|
+
!type.param_location_path?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
self.class.new(attributes: body_params)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
concerning :Webpage do
|
|
53
|
+
def summary
|
|
54
|
+
"object"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def partial
|
|
58
|
+
"explicit/documentation/type/record"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def has_details?
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
concerning :Swagger do
|
|
67
|
+
def swagger_parameters
|
|
68
|
+
attributes.map do |name, type|
|
|
69
|
+
{
|
|
70
|
+
name:,
|
|
71
|
+
in: type.param_location_path? ? "path" : "body",
|
|
72
|
+
description: type.description,
|
|
73
|
+
required: !type.nilable,
|
|
74
|
+
schema: type.swagger_schema
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def swagger_schema
|
|
80
|
+
properties = attributes.to_h do |name, type|
|
|
81
|
+
[name, type.swagger_schema]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
required = attributes.filter_map do |name, type|
|
|
85
|
+
type.required? ? name.to_s : nil
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
type: "object",
|
|
90
|
+
properties:,
|
|
91
|
+
required:,
|
|
92
|
+
description: swagger_description([])
|
|
93
|
+
}.compact_blank
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|