explicit 0.2.14 → 0.2.16
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 +144 -9
- data/app/views/explicit/documentation/_page.html.erb +1 -1
- data/app/views/explicit/documentation/type/_big_decimal.html.erb +20 -0
- data/config/locales/en.yml +1 -0
- data/lib/explicit/documentation/builder.rb +1 -1
- data/lib/explicit/documentation/output/swagger.rb +21 -2
- data/lib/explicit/documentation/output/webpage.rb +4 -3
- data/lib/explicit/documentation.rb +1 -1
- data/lib/explicit/mcp_server/builder.rb +50 -0
- data/lib/explicit/mcp_server/request.rb +42 -0
- data/lib/explicit/mcp_server/response.rb +29 -0
- data/lib/explicit/mcp_server/router.rb +84 -0
- data/lib/explicit/mcp_server/tool.rb +20 -0
- data/lib/explicit/mcp_server.rb +39 -0
- data/lib/explicit/request.rb +35 -1
- data/lib/explicit/type/agreement.rb +7 -9
- data/lib/explicit/type/any.rb +4 -4
- data/lib/explicit/type/array.rb +6 -8
- data/lib/explicit/type/big_decimal.rb +36 -15
- data/lib/explicit/type/boolean.rb +4 -6
- data/lib/explicit/type/date.rb +9 -11
- data/lib/explicit/type/date_range.rb +11 -13
- data/lib/explicit/type/date_time_iso8601.rb +9 -11
- data/lib/explicit/type/date_time_iso8601_range.rb +10 -12
- data/lib/explicit/type/date_time_unix_epoch.rb +9 -11
- data/lib/explicit/type/enum.rb +5 -7
- data/lib/explicit/type/file.rb +9 -11
- data/lib/explicit/type/float.rb +12 -14
- data/lib/explicit/type/hash.rb +8 -10
- data/lib/explicit/type/integer.rb +12 -14
- data/lib/explicit/type/literal.rb +5 -7
- data/lib/explicit/type/one_of.rb +3 -5
- data/lib/explicit/type/record.rb +12 -25
- data/lib/explicit/type/string.rb +11 -13
- data/lib/explicit/type.rb +10 -2
- data/lib/explicit/version.rb +1 -1
- data/lib/explicit.rb +7 -0
- metadata +9 -6
@@ -26,14 +26,12 @@ class Explicit::Type::Agreement < Explicit::Type
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
})
|
37
|
-
end
|
29
|
+
def json_schema(flavour)
|
30
|
+
{
|
31
|
+
type: "boolean",
|
32
|
+
description_topics: [
|
33
|
+
swagger_i18n("agreement")
|
34
|
+
]
|
35
|
+
}
|
38
36
|
end
|
39
37
|
end
|
data/lib/explicit/type/any.rb
CHANGED
data/lib/explicit/type/array.rb
CHANGED
@@ -43,13 +43,11 @@ class Explicit::Type::Array < Explicit::Type
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
})
|
53
|
-
end
|
46
|
+
def json_schema(flavour)
|
47
|
+
{
|
48
|
+
type: "array",
|
49
|
+
items: item_type.mcp_schema,
|
50
|
+
minItems: empty ? 0 : 1
|
51
|
+
}
|
54
52
|
end
|
55
53
|
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Explicit::Type::BigDecimal < Explicit::Type
|
4
|
-
attr_reader :min, :max
|
4
|
+
attr_reader :min, :max, :negative, :positive
|
5
5
|
|
6
|
-
def initialize(min: nil, max: nil)
|
6
|
+
def initialize(min: nil, max: nil, negative: nil, positive: nil)
|
7
7
|
@min = min
|
8
8
|
@max = max
|
9
|
+
@negative = negative
|
10
|
+
@positive = positive
|
9
11
|
end
|
10
12
|
|
11
13
|
def validate(value)
|
@@ -23,6 +25,22 @@ class Explicit::Type::BigDecimal < Explicit::Type
|
|
23
25
|
return error_i18n("max", max:)
|
24
26
|
end
|
25
27
|
|
28
|
+
if negative == false && decimal_value < 0
|
29
|
+
return error_i18n("not_negative")
|
30
|
+
end
|
31
|
+
|
32
|
+
if negative == true && decimal_value >= 0
|
33
|
+
return error_i18n("only_negative")
|
34
|
+
end
|
35
|
+
|
36
|
+
if positive == false && decimal_value > 0
|
37
|
+
return error_i18n("not_positive")
|
38
|
+
end
|
39
|
+
|
40
|
+
if positive == true && decimal_value <= 0
|
41
|
+
return error_i18n("only_positive")
|
42
|
+
end
|
43
|
+
|
26
44
|
[:ok, decimal_value]
|
27
45
|
rescue ArgumentError
|
28
46
|
return error_i18n("big_decimal")
|
@@ -30,7 +48,7 @@ class Explicit::Type::BigDecimal < Explicit::Type
|
|
30
48
|
|
31
49
|
concerning :Webpage do
|
32
50
|
def summary
|
33
|
-
"string"
|
51
|
+
"decimal string"
|
34
52
|
end
|
35
53
|
|
36
54
|
def partial
|
@@ -42,17 +60,20 @@ class Explicit::Type::BigDecimal < Explicit::Type
|
|
42
60
|
end
|
43
61
|
end
|
44
62
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
63
|
+
def json_schema(flavour)
|
64
|
+
{
|
65
|
+
type: "string",
|
66
|
+
pattern: /^\d*\.?\d*$/.inspect[1..-2],
|
67
|
+
format: "decimal number",
|
68
|
+
description_topics: [
|
69
|
+
swagger_i18n("big_decimal_format"),
|
70
|
+
min&.then { swagger_i18n("big_decimal_min", min: _1) },
|
71
|
+
max&.then { swagger_i18n("big_decimal_max", max: _1) },
|
72
|
+
positive == false ? swagger_i18n("number_not_positive") : nil,
|
73
|
+
positive == true ? swagger_i18n("number_only_positive") : nil,
|
74
|
+
negative == false ? swagger_i18n("number_not_negative") : nil,
|
75
|
+
negative == true ? swagger_i18n("number_only_negative") : nil
|
76
|
+
].compact
|
77
|
+
}
|
57
78
|
end
|
58
79
|
end
|
data/lib/explicit/type/date.rb
CHANGED
@@ -51,16 +51,14 @@ class Explicit::Type::Date < Explicit::Type
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
})
|
64
|
-
end
|
54
|
+
def json_schema(flavour)
|
55
|
+
{
|
56
|
+
type: "string",
|
57
|
+
pattern: /\d{4}-\d{2}-\d{2}/.inspect[1..-2],
|
58
|
+
format: "date",
|
59
|
+
description_topics: [
|
60
|
+
swagger_i18n("date_format")
|
61
|
+
]
|
62
|
+
}
|
65
63
|
end
|
66
64
|
end
|
@@ -78,18 +78,16 @@ class Explicit::Type::DateRange < Explicit::Type
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
})
|
93
|
-
end
|
81
|
+
def json_schema(flavour)
|
82
|
+
{
|
83
|
+
type: "string",
|
84
|
+
pattern: FORMAT.inspect[1..-2],
|
85
|
+
format: "date range",
|
86
|
+
description_topics: [
|
87
|
+
swagger_i18n("date_range"),
|
88
|
+
min_range&.then { swagger_i18n("date_range_min_range", min_range: _1.inspect) },
|
89
|
+
max_range&.then { swagger_i18n("date_range_max_range", max_range: _1.inspect) },
|
90
|
+
]
|
91
|
+
}
|
94
92
|
end
|
95
93
|
end
|
@@ -52,15 +52,13 @@ class Explicit::Type::DateTimeISO8601 < Explicit::Type
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
})
|
64
|
-
end
|
55
|
+
def json_schema(flavour)
|
56
|
+
{
|
57
|
+
type: "string",
|
58
|
+
format: "date-time",
|
59
|
+
description_topics: [
|
60
|
+
swagger_i18n("date_time_iso8601")
|
61
|
+
]
|
62
|
+
}
|
65
63
|
end
|
66
|
-
end
|
64
|
+
end
|
@@ -92,17 +92,15 @@ class Explicit::Type::DateTimeISO8601Range < Explicit::Type
|
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
})
|
106
|
-
end
|
95
|
+
def json_schema(flavour)
|
96
|
+
{
|
97
|
+
type: "string",
|
98
|
+
format: "date time range",
|
99
|
+
description_topics: [
|
100
|
+
swagger_i18n("date_time_iso8601_range"),
|
101
|
+
min_range&.then { swagger_i18n("date_time_iso8601_range_min_range", min_range: _1.inspect) },
|
102
|
+
max_range&.then { swagger_i18n("date_time_iso8601_range_max_range", max_range: _1.inspect) },
|
103
|
+
]
|
104
|
+
}
|
107
105
|
end
|
108
106
|
end
|
@@ -54,16 +54,14 @@ class Explicit::Type::DateTimeUnixEpoch < Explicit::Type
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
})
|
67
|
-
end
|
57
|
+
def json_schema(flavour)
|
58
|
+
{
|
59
|
+
type: "integer",
|
60
|
+
minimum: 1,
|
61
|
+
format: "POSIX time",
|
62
|
+
description_topics: [
|
63
|
+
swagger_i18n("date_time_unix_epoch")
|
64
|
+
]
|
65
|
+
}
|
68
66
|
end
|
69
67
|
end
|
data/lib/explicit/type/enum.rb
CHANGED
@@ -29,12 +29,10 @@ class Explicit::Type::Enum < Explicit::Type
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
})
|
38
|
-
end
|
32
|
+
def json_schema(flavour)
|
33
|
+
{
|
34
|
+
type: "string",
|
35
|
+
enum: allowed_values
|
36
|
+
}
|
39
37
|
end
|
40
38
|
end
|
data/lib/explicit/type/file.rb
CHANGED
@@ -45,16 +45,14 @@ class Explicit::Type::File < Explicit::Type
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
})
|
58
|
-
end
|
48
|
+
def json_schema(flavour)
|
49
|
+
{
|
50
|
+
type: "string",
|
51
|
+
format: "binary",
|
52
|
+
description_topics: [
|
53
|
+
max_size&.then { swagger_i18n("file_max_size", max_size: number_to_human_size(_1)) },
|
54
|
+
content_types.any? ? swagger_i18n("file_content_types", content_types: content_types.join(', ')) : nil
|
55
|
+
]
|
56
|
+
}
|
59
57
|
end
|
60
58
|
end
|
data/lib/explicit/type/float.rb
CHANGED
@@ -69,19 +69,17 @@ class Explicit::Type::Float < Explicit::Type
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
}.compact_blank)
|
85
|
-
end
|
72
|
+
def json_schema(flavour)
|
73
|
+
{
|
74
|
+
type: "number",
|
75
|
+
minimum: min,
|
76
|
+
maximum: max,
|
77
|
+
description_topics: [
|
78
|
+
positive == false ? swagger_i18n("number_not_positive") : nil,
|
79
|
+
positive == true ? swagger_i18n("number_only_positive") : nil,
|
80
|
+
negative == false ? swagger_i18n("number_not_negative") : nil,
|
81
|
+
negative == true ? swagger_i18n("number_only_negative") : nil
|
82
|
+
].compact_blank
|
83
|
+
}.compact_blank
|
86
84
|
end
|
87
85
|
end
|
data/lib/explicit/type/hash.rb
CHANGED
@@ -46,15 +46,13 @@ class Explicit::Type::Hash < Explicit::Type
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
})
|
58
|
-
end
|
49
|
+
def json_schema(flavour)
|
50
|
+
{
|
51
|
+
type: "object",
|
52
|
+
additionalProperties: value_type.mcp_schema,
|
53
|
+
description_topics: [
|
54
|
+
empty == false ? swagger_i18n("hash_not_empty") : nil
|
55
|
+
]
|
56
|
+
}
|
59
57
|
end
|
60
58
|
end
|
@@ -69,19 +69,17 @@ class Explicit::Type::Integer < Explicit::Type
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
}.compact_blank)
|
85
|
-
end
|
72
|
+
def json_schema(flavour)
|
73
|
+
{
|
74
|
+
type: "integer",
|
75
|
+
minimum: min,
|
76
|
+
maximum: max,
|
77
|
+
description_topics: [
|
78
|
+
positive == false ? swagger_i18n("number_not_positive") : nil,
|
79
|
+
positive == true ? swagger_i18n("number_only_positive") : nil,
|
80
|
+
negative == false ? swagger_i18n("number_not_negative") : nil,
|
81
|
+
negative == true ? swagger_i18n("number_only_negative") : nil
|
82
|
+
].compact_blank
|
83
|
+
}.compact_blank
|
86
84
|
end
|
87
85
|
end
|
@@ -33,12 +33,10 @@ class Explicit::Type::Literal < Explicit::Type
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
})
|
42
|
-
end
|
36
|
+
def json_schema(flavour)
|
37
|
+
{
|
38
|
+
type: @value.is_a?(::String) ? "string" : "integer",
|
39
|
+
enum: [@value]
|
40
|
+
}
|
43
41
|
end
|
44
42
|
end
|
data/lib/explicit/type/one_of.rb
CHANGED
@@ -101,11 +101,9 @@ class Explicit::Type::OneOf < Explicit::Type
|
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
return subtypes.first.swagger_schema if subtypes.one?
|
104
|
+
def json_schema(flavour)
|
105
|
+
raise ::NotImplementedError if flavour == :mcp
|
107
106
|
|
108
|
-
|
109
|
-
end
|
107
|
+
{ oneOf: subtypes.map(&:swagger_schema) }
|
110
108
|
end
|
111
109
|
end
|
data/lib/explicit/type/record.rb
CHANGED
@@ -73,33 +73,20 @@ class Explicit::Type::Record < Explicit::Type
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
{
|
80
|
-
name:,
|
81
|
-
in: type.param_location_path? ? "path" : "body",
|
82
|
-
description: type.description,
|
83
|
-
required: !type.nilable,
|
84
|
-
schema: type.swagger_schema
|
85
|
-
}
|
86
|
-
end
|
76
|
+
def json_schema(flavour)
|
77
|
+
properties = attributes.to_h do |name, type|
|
78
|
+
[ name, flavour == :mcp ? type.mcp_schema : type.swagger_schema ]
|
87
79
|
end
|
88
80
|
|
89
|
-
|
90
|
-
|
91
|
-
[ name, type.swagger_schema ]
|
92
|
-
end
|
93
|
-
|
94
|
-
required = attributes.filter_map do |name, type|
|
95
|
-
type.required? ? name.to_s : nil
|
96
|
-
end
|
97
|
-
|
98
|
-
merge_base_swagger_schema({
|
99
|
-
type: "object",
|
100
|
-
properties:,
|
101
|
-
required:
|
102
|
-
}.compact_blank)
|
81
|
+
required = attributes.filter_map do |name, type|
|
82
|
+
type.required? ? name.to_s : nil
|
103
83
|
end
|
84
|
+
|
85
|
+
{
|
86
|
+
type: "object",
|
87
|
+
properties:,
|
88
|
+
required:,
|
89
|
+
additionalProperties: false
|
90
|
+
}.compact
|
104
91
|
end
|
105
92
|
end
|
data/lib/explicit/type/string.rb
CHANGED
@@ -51,18 +51,16 @@ class Explicit::Type::String < Explicit::Type
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
}.compact_blank)
|
66
|
-
end
|
54
|
+
def json_schema(flavour)
|
55
|
+
{
|
56
|
+
type: "string",
|
57
|
+
pattern: format&.inspect&.then { _1[1..-2] },
|
58
|
+
minLength: min_length || (empty == false ? 1 : nil),
|
59
|
+
maxLength: max_length,
|
60
|
+
description_topics: [
|
61
|
+
empty == false ? swagger_i18n("string_not_empty") : nil,
|
62
|
+
downcase == true ? swagger_i18n("string_downcase") : nil
|
63
|
+
].compact_blank
|
64
|
+
}.compact_blank
|
67
65
|
end
|
68
66
|
end
|
data/lib/explicit/type.rb
CHANGED
@@ -130,7 +130,7 @@ class Explicit::Type
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def required?
|
133
|
-
!nilable
|
133
|
+
!nilable && default.blank?
|
134
134
|
end
|
135
135
|
|
136
136
|
def error_i18n(name, context = {})
|
@@ -156,7 +156,15 @@ class Explicit::Type
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
-
def
|
159
|
+
def swagger_schema
|
160
|
+
merge_base_json_schema(json_schema(:swagger))
|
161
|
+
end
|
162
|
+
|
163
|
+
def mcp_schema
|
164
|
+
merge_base_json_schema(json_schema(:mcp))
|
165
|
+
end
|
166
|
+
|
167
|
+
def merge_base_json_schema(attributes)
|
160
168
|
topics = attributes.delete(:description_topics)&.compact_blank || []
|
161
169
|
|
162
170
|
formatted_description =
|
data/lib/explicit/version.rb
CHANGED
data/lib/explicit.rb
CHANGED
@@ -4,6 +4,13 @@ require "explicit/configuration"
|
|
4
4
|
require "explicit/engine"
|
5
5
|
require "explicit/version"
|
6
6
|
|
7
|
+
require "explicit/mcp_server"
|
8
|
+
require "explicit/mcp_server/builder"
|
9
|
+
require "explicit/mcp_server/request"
|
10
|
+
require "explicit/mcp_server/router"
|
11
|
+
require "explicit/mcp_server/response"
|
12
|
+
require "explicit/mcp_server/tool"
|
13
|
+
|
7
14
|
require "explicit/documentation"
|
8
15
|
require "explicit/documentation/builder"
|
9
16
|
require "explicit/documentation/markdown"
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: explicit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luiz Vasconcellos
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: rails
|
@@ -86,6 +85,12 @@ files:
|
|
86
85
|
- lib/explicit/documentation/page/request.rb
|
87
86
|
- lib/explicit/documentation/section.rb
|
88
87
|
- lib/explicit/engine.rb
|
88
|
+
- lib/explicit/mcp_server.rb
|
89
|
+
- lib/explicit/mcp_server/builder.rb
|
90
|
+
- lib/explicit/mcp_server/request.rb
|
91
|
+
- lib/explicit/mcp_server/response.rb
|
92
|
+
- lib/explicit/mcp_server/router.rb
|
93
|
+
- lib/explicit/mcp_server/tool.rb
|
89
94
|
- lib/explicit/request.rb
|
90
95
|
- lib/explicit/request/example.rb
|
91
96
|
- lib/explicit/request/invalid_params_error.rb
|
@@ -128,7 +133,6 @@ metadata:
|
|
128
133
|
homepage_uri: https://github.com/luizpvas/explicit
|
129
134
|
source_code_uri: https://github.com/luizpvas/explicit
|
130
135
|
changelog_uri: https://github.com/luizpvas/explicit
|
131
|
-
post_install_message:
|
132
136
|
rdoc_options: []
|
133
137
|
require_paths:
|
134
138
|
- lib
|
@@ -143,8 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
147
|
- !ruby/object:Gem::Version
|
144
148
|
version: '0'
|
145
149
|
requirements: []
|
146
|
-
rubygems_version: 3.
|
147
|
-
signing_key:
|
150
|
+
rubygems_version: 3.6.7
|
148
151
|
specification_version: 4
|
149
152
|
summary: Explicit is a validation and documentation library for REST APIs
|
150
153
|
test_files: []
|