tiki 0.0.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/Gemfile +8 -0
- data/bin/tiki +4 -0
- data/lib/tiki/components.rb +76 -0
- data/lib/tiki/content.rb +36 -0
- data/lib/tiki/external-documentation.rb +16 -0
- data/lib/tiki/list-helpers.rb +57 -0
- data/lib/tiki/media-type.rb +32 -0
- data/lib/tiki/operation.rb +88 -0
- data/lib/tiki/parameter.rb +48 -0
- data/lib/tiki/path-item.rb +71 -0
- data/lib/tiki/props.rb +96 -0
- data/lib/tiki/reason.rb +66 -0
- data/lib/tiki/reference.rb +21 -0
- data/lib/tiki/request-body.rb +27 -0
- data/lib/tiki/response.rb +27 -0
- data/lib/tiki/response.spec.rb +160 -0
- data/lib/tiki/schema.rb +301 -0
- data/lib/tiki/schema.spec.rb +33 -0
- data/lib/tiki/server.rb +69 -0
- data/lib/tiki/server.spec.rb +51 -0
- data/lib/tiki/spec.rb +159 -0
- data/lib/tiki/spec.spec.rb +65 -0
- data/lib/tiki.rb +28 -0
- metadata +81 -0
@@ -0,0 +1,160 @@
|
|
1
|
+
require_relative './response'
|
2
|
+
|
3
|
+
describe do
|
4
|
+
let(:response) { Response.new 'My Response' }
|
5
|
+
|
6
|
+
describe 'a minimal response' do
|
7
|
+
it 'should return a correct spec' do
|
8
|
+
expect(response.to_spec).to eq({ description: 'My Response' })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'content' do
|
13
|
+
describe 'default mime type' do
|
14
|
+
before do
|
15
|
+
response.content
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return a correct spec' do
|
19
|
+
expect(response.to_spec).to eq(
|
20
|
+
{
|
21
|
+
description: 'My Response',
|
22
|
+
content: {
|
23
|
+
'application/json' => {
|
24
|
+
schema: { type: :object }
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'a schema' do
|
34
|
+
describe 'a schema type' do
|
35
|
+
before do
|
36
|
+
response.schema :object
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should return a correct spec' do
|
40
|
+
expect(response.to_spec).to eq(
|
41
|
+
{
|
42
|
+
description: 'My Response',
|
43
|
+
content: {
|
44
|
+
'application/json' => {
|
45
|
+
schema: {
|
46
|
+
type: :object
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'a ref' do
|
56
|
+
before do
|
57
|
+
response.schema ref: :Address
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should return a correct spec' do
|
61
|
+
expect(response.to_spec).to eq(
|
62
|
+
{
|
63
|
+
description: 'My Response',
|
64
|
+
content: {
|
65
|
+
'application/json' => {
|
66
|
+
schema: {
|
67
|
+
:$ref => '#/components/schemas/Address'
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe 'an array' do
|
78
|
+
describe 'a items schema type' do
|
79
|
+
before do
|
80
|
+
response.array :string
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should return a correct spec' do
|
84
|
+
expect(response.to_spec).to eq(
|
85
|
+
{
|
86
|
+
description: 'My Response',
|
87
|
+
content: {
|
88
|
+
'application/json' => {
|
89
|
+
schema: {
|
90
|
+
type: :array,
|
91
|
+
items: { type: :string }
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'a items ref' do
|
100
|
+
before do
|
101
|
+
response.array ref: :Address
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should return a correct spec' do
|
105
|
+
expect(response.to_spec).to eq(
|
106
|
+
{
|
107
|
+
description: 'My Response',
|
108
|
+
content: {
|
109
|
+
'application/json' => {
|
110
|
+
schema: {
|
111
|
+
type: :array,
|
112
|
+
items: { :$ref => '#/components/schemas/Address' }
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'an object' do
|
124
|
+
before do
|
125
|
+
response.object
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should return a correct spec' do
|
129
|
+
expect(response.to_spec).to eq(
|
130
|
+
{
|
131
|
+
description: 'My Response',
|
132
|
+
content: {
|
133
|
+
'application/json' => {
|
134
|
+
schema: { type: :object }
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'a ref' do
|
143
|
+
before do
|
144
|
+
response.ref :Address
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should return a correct spec' do
|
148
|
+
expect(response.to_spec).to eq(
|
149
|
+
{
|
150
|
+
description: 'My Response',
|
151
|
+
content: {
|
152
|
+
'application/json' => {
|
153
|
+
schema: { :$ref => '#/components/schemas/Address' }
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/tiki/schema.rb
ADDED
@@ -0,0 +1,301 @@
|
|
1
|
+
require_relative './props'
|
2
|
+
require_relative './reference'
|
3
|
+
require_relative './list-helpers'
|
4
|
+
|
5
|
+
using Props
|
6
|
+
|
7
|
+
PRIMITIVES = %i[string integer number boolean].freeze
|
8
|
+
DATA_TYPES = PRIMITIVES + %i[object array]
|
9
|
+
|
10
|
+
FORMATS = [
|
11
|
+
[:integer, %i[int32 int64]],
|
12
|
+
[:number, %i[float double]],
|
13
|
+
[:string, %i[byte binary date date_time datetime password], { date_time: 'date-time', datetime: 'date-time' }]
|
14
|
+
|
15
|
+
].freeze
|
16
|
+
|
17
|
+
NUMBER_PROPS = %i[
|
18
|
+
minimum
|
19
|
+
maximum
|
20
|
+
exclusive_minimum
|
21
|
+
exclusive_maximum
|
22
|
+
multiple_of
|
23
|
+
].freeze
|
24
|
+
|
25
|
+
STRING_PROPS = %i[
|
26
|
+
min_length
|
27
|
+
max_length
|
28
|
+
pattern
|
29
|
+
].freeze
|
30
|
+
|
31
|
+
OBJECT_PROPS = %i[
|
32
|
+
min_properties
|
33
|
+
max_properties
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
MARKER_PROPS = %i[
|
37
|
+
unique_items
|
38
|
+
nullable
|
39
|
+
read_only
|
40
|
+
write_only
|
41
|
+
].freeze
|
42
|
+
|
43
|
+
class Schema
|
44
|
+
props :title, :description, :format, NUMBER_PROPS, STRING_PROPS
|
45
|
+
marker_props MARKER_PROPS
|
46
|
+
named_props :format, MARKER_PROPS, NUMBER_PROPS, STRING_PROPS, OBJECT_PROPS
|
47
|
+
scalar_props :type, :title, :description, :format, :enum, MARKER_PROPS, NUMBER_PROPS, STRING_PROPS, OBJECT_PROPS
|
48
|
+
object_props :items, :all_of, :one_of, :any_of, :discriminator
|
49
|
+
hash_props :properties
|
50
|
+
object_or_scalar_props :additional_properties
|
51
|
+
|
52
|
+
def initialize(type = nil, title = nil, enum: nil, additional_properties: nil, min: nil, max: nil, length: nil,
|
53
|
+
range: nil, **named)
|
54
|
+
case type
|
55
|
+
when *PRIMITIVES, :object, :array
|
56
|
+
@type = type
|
57
|
+
when String, Symbol
|
58
|
+
@ref = create_reference type
|
59
|
+
when Array
|
60
|
+
@type = :array
|
61
|
+
items type.first
|
62
|
+
when OrList
|
63
|
+
one_of(*type.list)
|
64
|
+
when AndList
|
65
|
+
all_of(*type.list)
|
66
|
+
end
|
67
|
+
additional_properties(additional_properties) if additional_properties
|
68
|
+
enum(enum) if enum
|
69
|
+
length(length) if length.is_a? Range
|
70
|
+
range(range) if range.is_a? Range
|
71
|
+
named_props named
|
72
|
+
@title = title
|
73
|
+
min(min) if min
|
74
|
+
max(max) if max
|
75
|
+
end
|
76
|
+
|
77
|
+
def length(length)
|
78
|
+
return unless length.is_a? Range
|
79
|
+
|
80
|
+
@max_length = length.max
|
81
|
+
@min_length = length.min
|
82
|
+
end
|
83
|
+
|
84
|
+
def range(range)
|
85
|
+
return unless range.is_a? Range
|
86
|
+
|
87
|
+
@maximum = range.max + (range.exclude_end? ? 1 : 0)
|
88
|
+
@minimum = range.min
|
89
|
+
@exclusive_maximum = range.exclude_end? || nil
|
90
|
+
end
|
91
|
+
|
92
|
+
def min(min)
|
93
|
+
case @type
|
94
|
+
when :number, :integer
|
95
|
+
minimum min
|
96
|
+
when :string
|
97
|
+
min_length min
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def max(max)
|
102
|
+
case @type
|
103
|
+
when :number, :integer
|
104
|
+
maximum max
|
105
|
+
when :string
|
106
|
+
max_length max
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def unique_items
|
111
|
+
@unique_items = true
|
112
|
+
end
|
113
|
+
|
114
|
+
def nullable
|
115
|
+
@nullable = true
|
116
|
+
end
|
117
|
+
|
118
|
+
def read_only
|
119
|
+
@read_only = true
|
120
|
+
end
|
121
|
+
|
122
|
+
def items(type = nil, title = nil, &block)
|
123
|
+
@items = Schema.new type, title
|
124
|
+
instance_eval(&block) if block
|
125
|
+
end
|
126
|
+
|
127
|
+
def enum(*items)
|
128
|
+
@type ||= :string
|
129
|
+
@enum = items.flatten
|
130
|
+
@nullable = true if @enum.include? nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def property(name, type = :string, _title = nil, optional: false, ref: nil, **named, &block)
|
134
|
+
@type ||= :object
|
135
|
+
name_str = name.to_s
|
136
|
+
if name_str.end_with? '?'
|
137
|
+
optional = true
|
138
|
+
name_str = name_str[0..-2]
|
139
|
+
end
|
140
|
+
unless optional
|
141
|
+
@required ||= []
|
142
|
+
@required << name_str
|
143
|
+
end
|
144
|
+
@properties ||= []
|
145
|
+
if ref
|
146
|
+
@properties << [name_str, Reference.new(ref)]
|
147
|
+
else
|
148
|
+
schema = Schema.new type, **named
|
149
|
+
schema.instance_eval(&block) if block
|
150
|
+
@properties << [name_str, schema]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def additional_properties(type = nil, ref: nil, &block)
|
155
|
+
if ref
|
156
|
+
@additional_properties = Reference.new ref
|
157
|
+
elsif type.is_a? Symbol
|
158
|
+
schema = Schema.new type
|
159
|
+
schema.instance_eval(&block) if block
|
160
|
+
@additional_properties = schema
|
161
|
+
else
|
162
|
+
@additional_properties = true
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def object(name, title = nil, **named, &block)
|
167
|
+
property name, :object, title, **named, &block
|
168
|
+
end
|
169
|
+
|
170
|
+
def object?(name, title = nil, **named, &block)
|
171
|
+
object name, title, optional: true, **named, &block
|
172
|
+
end
|
173
|
+
|
174
|
+
def any(name, title = nil, **named, &block)
|
175
|
+
property name, :any, title, **named, &block
|
176
|
+
end
|
177
|
+
|
178
|
+
def any?(name, title = nil, **named, &block)
|
179
|
+
any name, title, optional: true, **named, &block
|
180
|
+
end
|
181
|
+
|
182
|
+
def ref(name, ref, **named)
|
183
|
+
property name, ref: ref, **named
|
184
|
+
end
|
185
|
+
|
186
|
+
def ref?(name, ref, **named)
|
187
|
+
ref(name, ref, optional: true, **named)
|
188
|
+
end
|
189
|
+
|
190
|
+
def refs(**named)
|
191
|
+
named.each_pair { |name, ref| property name, ref: ref }
|
192
|
+
end
|
193
|
+
|
194
|
+
def all_of(*refs, &block)
|
195
|
+
@all_of = SchemaList.new(*refs)
|
196
|
+
@all_of.instance_eval(&block) if block
|
197
|
+
end
|
198
|
+
|
199
|
+
def one_of(*refs, &block)
|
200
|
+
@one_of = SchemaList.new(*refs)
|
201
|
+
@one_of.instance_eval(&block) if block
|
202
|
+
end
|
203
|
+
|
204
|
+
def any_of(*refs, &block)
|
205
|
+
@any_of = SchemaList.new(*refs)
|
206
|
+
@any_of.instance_eval(&block) if block
|
207
|
+
end
|
208
|
+
|
209
|
+
def discriminator(property_name = nil, **mapping, &block)
|
210
|
+
@discriminator = Discriminator.new property_name, **mapping, &block
|
211
|
+
end
|
212
|
+
|
213
|
+
def to_spec
|
214
|
+
if @type == :any
|
215
|
+
{}
|
216
|
+
elsif @ref
|
217
|
+
{ '$ref': @ref }
|
218
|
+
else
|
219
|
+
props = {}
|
220
|
+
scalar_props props
|
221
|
+
object_props props
|
222
|
+
hash_props props
|
223
|
+
object_or_scalar_props props
|
224
|
+
props[:required] = @required if @required
|
225
|
+
props
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def self.property_shortcuts(shortcut_name)
|
230
|
+
define_method "#{shortcut_name}?" do |name, title = nil, **named, &block|
|
231
|
+
send shortcut_name, name, title, optional: true, **named, &block
|
232
|
+
end
|
233
|
+
define_method "#{shortcut_name}s" do |*names|
|
234
|
+
names.each { |name| send shortcut_name, name }
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
PRIMITIVES.each do |primitive|
|
239
|
+
define_method primitive do |name, title = nil, **named, &block|
|
240
|
+
property name, primitive, title, **named, &block
|
241
|
+
end
|
242
|
+
property_shortcuts primitive
|
243
|
+
end
|
244
|
+
|
245
|
+
FORMATS.each do |(primitive, formats, mapping)|
|
246
|
+
formats.each do |format|
|
247
|
+
format_str = (mapping && mapping[format]) || format.to_s
|
248
|
+
define_method format do |name, title = nil, **named, &block|
|
249
|
+
send primitive, name, title, format: format_str, **named, &block
|
250
|
+
end
|
251
|
+
property_shortcuts format
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class SchemaList
|
257
|
+
def initialize(*types)
|
258
|
+
@schemas = types.map { |type| Schema.new(type) }
|
259
|
+
end
|
260
|
+
|
261
|
+
def schema(type: :object, ref: nil, **named, &block)
|
262
|
+
if ref
|
263
|
+
@schemas << Reference.new(ref)
|
264
|
+
else
|
265
|
+
schema = Schema.new type, **named
|
266
|
+
schema.instance_eval(&block) if block
|
267
|
+
@schemas << schema
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def ref(ref)
|
272
|
+
schema(ref: ref)
|
273
|
+
end
|
274
|
+
|
275
|
+
def to_spec
|
276
|
+
@schemas.map(&:to_spec)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
class Discriminator
|
281
|
+
props :property_name
|
282
|
+
scalar_props :property_name
|
283
|
+
|
284
|
+
def initialize(property_name = nil, **mapping)
|
285
|
+
@property_name = property_name
|
286
|
+
@mapping = mapping.transform_values { |ref| Reference.new ref }
|
287
|
+
end
|
288
|
+
|
289
|
+
def mapping(**mapping)
|
290
|
+
@mapping.merge! mapping
|
291
|
+
end
|
292
|
+
|
293
|
+
def to_spec
|
294
|
+
props = {}
|
295
|
+
scalar_props props
|
296
|
+
props[:mapping] = @mapping.transform_values(&:ref) unless @mapping.empty?
|
297
|
+
props
|
298
|
+
end
|
299
|
+
|
300
|
+
alias property property_name
|
301
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative './schema.rb'
|
2
|
+
|
3
|
+
describe do
|
4
|
+
describe 'a string schema' do
|
5
|
+
let(:schema) { Schema.new :string }
|
6
|
+
it 'should return a spec with type object' do
|
7
|
+
expect(schema.to_spec).to eq({ type: :string })
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'a string schema with max_length' do
|
12
|
+
let(:schema) { Schema.new :string, max_length: 80 }
|
13
|
+
it 'should return a spec with type object' do
|
14
|
+
expect(schema.to_spec).to eq({ type: :string, maxLength: 80 })
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'an array schema with string items' do
|
19
|
+
let(:schema) { Schema.new :array }
|
20
|
+
it 'should return a spec with string items' do
|
21
|
+
schema.items :string
|
22
|
+
expect(schema.to_spec).to eq({ type: :array, items: { type: :string } })
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'an object schema with a string property' do
|
27
|
+
let(:schema) { Schema.new :object }
|
28
|
+
it 'should return a spec with a property' do
|
29
|
+
schema.property :foo, :string
|
30
|
+
expect(schema.to_spec).to eq({ type: :object, properties: { foo: { type: :string } } })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/tiki/server.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative './props'
|
2
|
+
|
3
|
+
using Props
|
4
|
+
|
5
|
+
class ServerVariable
|
6
|
+
props :default, :enum, :description
|
7
|
+
named_props :enum
|
8
|
+
scalar_props :default, :enum, :description
|
9
|
+
|
10
|
+
def initialize(default = nil, **named)
|
11
|
+
@default = default
|
12
|
+
named_props named
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_spec
|
16
|
+
@default = @default&.to_s
|
17
|
+
@enum&.map!(&:to_s)
|
18
|
+
scalar_props
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Server
|
23
|
+
props :url, :description
|
24
|
+
scalar_props :url, :description
|
25
|
+
hash_props :variables
|
26
|
+
|
27
|
+
def initialize(url = nil, description = nil)
|
28
|
+
@url = url
|
29
|
+
@description = description
|
30
|
+
end
|
31
|
+
|
32
|
+
def variable(name, default = nil, **named, &block)
|
33
|
+
@variables ||= []
|
34
|
+
variable = ServerVariable.new default, **named
|
35
|
+
variable.instance_eval(&block) if block
|
36
|
+
@variables << [name, variable]
|
37
|
+
end
|
38
|
+
|
39
|
+
def variables(**vars)
|
40
|
+
vars.each_pair do |name, value|
|
41
|
+
if value.is_a? Array
|
42
|
+
variable name, value.first, enum: value
|
43
|
+
else
|
44
|
+
variable name, value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_spec
|
50
|
+
props = {}
|
51
|
+
scalar_props props
|
52
|
+
hash_props props
|
53
|
+
props
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module ServerMethods
|
58
|
+
def server(url = nil, description = nil, &block)
|
59
|
+
@servers ||= []
|
60
|
+
server = Server.new url, description
|
61
|
+
server.instance_eval(&block) if block
|
62
|
+
@servers << server
|
63
|
+
end
|
64
|
+
|
65
|
+
def servers(*singles, **pairs)
|
66
|
+
pairs.each_pair { |url, description| server url, description }
|
67
|
+
singles.each { |url| server url }
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative './server'
|
2
|
+
|
3
|
+
describe do
|
4
|
+
describe 'Server Object' do
|
5
|
+
describe 'an minimum Server' do
|
6
|
+
let(:server) { Server.new 'foo.bar/baz' }
|
7
|
+
|
8
|
+
it 'should return a correct spec' do
|
9
|
+
expect(server.to_spec).to eq(
|
10
|
+
{
|
11
|
+
url: 'foo.bar/baz'
|
12
|
+
}
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'a Server with variables' do
|
18
|
+
let(:server) { Server.new 'foo.bar/baz' }
|
19
|
+
before do
|
20
|
+
server.variable :foo, 'Foo'
|
21
|
+
server.variable :bar, 'Bar'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return a correct spec' do
|
25
|
+
expect(server.to_spec).to eq(
|
26
|
+
{
|
27
|
+
url: 'foo.bar/baz',
|
28
|
+
variables: {
|
29
|
+
foo: { default: 'Foo' },
|
30
|
+
bar: { default: 'Bar' }
|
31
|
+
}
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'Server Variable Object' do
|
39
|
+
let(:variable) { ServerVariable.new 'bar' }
|
40
|
+
|
41
|
+
describe 'a minimum Server Variable object' do
|
42
|
+
it 'should return a correct spec' do
|
43
|
+
expect(variable.to_spec).to eq(
|
44
|
+
{
|
45
|
+
default: 'bar'
|
46
|
+
}
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|