openapi_blocks 0.4.1 → 0.6.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/CHANGELOG.md +14 -0
- data/README.md +136 -52
- data/README.pt-BR.md +137 -53
- data/lib/generators/openapi_blocks/install/install_generator.rb +19 -0
- data/lib/generators/openapi_blocks/install/templates/initializer.rb.tt +36 -0
- data/lib/generators/openapi_blocks/openapi/openapi_generator.rb +15 -0
- data/lib/generators/openapi_blocks/openapi/templates/openapi.rb.tt +48 -0
- data/lib/generators/openapi_blocks/serializer/serializer_generator.rb +15 -0
- data/lib/generators/openapi_blocks/serializer/templates/serializer.rb.tt +15 -0
- data/lib/openapi_blocks/railtie.rb +6 -0
- data/lib/openapi_blocks/serialization.rb +19 -8
- data/lib/openapi_blocks/version.rb +1 -1
- metadata +12 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 61f36b05bd60171d8f0a821a4775d65af84b9180e4221b095a8eb49632af0a41
|
|
4
|
+
data.tar.gz: 604229f12f550977abad1b52859582490b4bb66cb1bce7694bb24a9b7c942324
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 470ab2f51a7f5a6434c2e3361e0f040cd81e9cd811324f114e14a56909d821b0a5e4fdb4a858b657929303c7f4f99b7ace5a424a76ff2d9b6bb994ea9c308c00
|
|
7
|
+
data.tar.gz: '0900adcc92411360fe6eebb836cf8c424ee45bd435a169f135a572f5d0efe3d55bfede29e6e618f5ae8ad3e48f060e4204161f8afdd3597f822e15b9bb59e1af'
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-06-03
|
|
11
|
+
|
|
12
|
+
- `OpenapiBlocks::Serializer` optmize serialization using frozen string constants as hash keys to reduce object allocations
|
|
13
|
+
|
|
14
|
+
## [0.5.0] - 2026-06-02
|
|
15
|
+
|
|
16
|
+
- Added generators
|
|
17
|
+
|
|
10
18
|
## [0.4.1] - 2026-06-02
|
|
11
19
|
|
|
12
20
|
- Change parallel version
|
|
@@ -146,5 +154,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
146
154
|
- `SpecController#ui` action serving Swagger UI with JSON/YAML spec switcher
|
|
147
155
|
|
|
148
156
|
[Unreleased]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.2.0...HEAD
|
|
157
|
+
[0.6.0]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.5.0...v0.6.0
|
|
158
|
+
[0.5.0]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.4.1...v0.5.0
|
|
159
|
+
[0.4.1]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.4.0...v0.4.1
|
|
160
|
+
[0.4.0]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.3.1...v0.4.0
|
|
161
|
+
[0.3.1]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.3.0...v0.3.1
|
|
162
|
+
[0.3.0]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.2.0...v0.3.0
|
|
149
163
|
[0.2.0]: https://github.com/evotechbuilder/openapi_blocks/compare/v0.1.0...v0.2.0
|
|
150
164
|
[0.1.0]: https://github.com/evotechbuilder/openapi_blocks/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# OpenapiBlocks
|
|
2
2
|
|
|
3
|
-
OpenapiBlocks is a Rails gem that automatically generates OpenAPI 3.0/3.1 documentation from your ActiveRecord models, ActiveModel validations, and Rails routes — inspired by
|
|
3
|
+
OpenapiBlocks is a Rails gem that automatically generates OpenAPI 3.0/3.1 documentation from your ActiveRecord models, ActiveModel validations, and Rails routes — inspired by ActiveModel::Serializer (https://github.com/rails-api/active_model_serializers).
|
|
4
4
|
|
|
5
|
-
Versão em português brasileiro:
|
|
5
|
+
Versão em português brasileiro: README.pt-BR.md
|
|
6
6
|
|
|
7
|
-
No manual annotation. No DSL noise in your controllers. Just declare what to expose and the spec is generated automatically. Includes a high-performance built-in serializer — ~3.6× faster than
|
|
7
|
+
No manual annotation. No DSL noise in your controllers. Just declare what to expose and the spec is generated automatically. Includes a high-performance built-in serializer — ~3.6× faster than as_json with consistent linear scaling from 10 to 5000 records.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
|
-
Add to your
|
|
13
|
+
Add to your Gemfile:
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
16
|
gem "openapi_blocks"
|
|
@@ -24,6 +24,70 @@ bundle install
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
+
## Generators
|
|
28
|
+
|
|
29
|
+
OpenapiBlocks provides three generators to get you started quickly.
|
|
30
|
+
|
|
31
|
+
### Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
rails generate openapi_blocks:install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Creates `config/initializers/openapi_blocks.rb` with all available options commented out, and mounts the engine in `config/routes.rb`:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
mount OpenapiBlocks::Engine => "/docs"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Openapi
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
rails generate openapi_blocks:openapi User
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Creates `app/openapi/user_openapi.rb` with all available DSL options commented out:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# app/openapi/user_openapi.rb
|
|
53
|
+
class UserOpenapi < OpenapiBlocks::Controller
|
|
54
|
+
# resource UserSerializer
|
|
55
|
+
# controller UsersController
|
|
56
|
+
|
|
57
|
+
# tags "Users"
|
|
58
|
+
|
|
59
|
+
# operation :index do
|
|
60
|
+
# summary "List all users"
|
|
61
|
+
# response 200, description: "List of users", schema: { type: :array, items: :User }
|
|
62
|
+
# end
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Serializer
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
rails generate openapi_blocks:serializer User
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Creates `app/serializers/user_serializer.rb` with all available DSL options commented out:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
# app/serializers/user_serializer.rb
|
|
76
|
+
class UserSerializer < OpenapiBlocks::Serializer
|
|
77
|
+
# ignore :password_digest, :reset_password_token
|
|
78
|
+
|
|
79
|
+
# association :posts, type: :array, read_only: true
|
|
80
|
+
# association :company
|
|
81
|
+
|
|
82
|
+
# attribute :full_name, type: :string, read_only: true
|
|
83
|
+
# def full_name
|
|
84
|
+
# "#{object.first_name} #{object.last_name}"
|
|
85
|
+
# end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
27
91
|
## Setup
|
|
28
92
|
|
|
29
93
|
### 1. Mount the Engine
|
|
@@ -48,7 +112,7 @@ GET /docs/openapi.yaml -> OpenAPI spec in YAML
|
|
|
48
112
|
|
|
49
113
|
### 2. Configure the initializer
|
|
50
114
|
|
|
51
|
-
|
|
115
|
+
OpenapiBlocks.configure is required. The gem raises OpenapiBlocks::Error on the first request if it was never called or if info.title / info.version are blank.
|
|
52
116
|
|
|
53
117
|
```ruby
|
|
54
118
|
# config/initializers/openapi_blocks.rb
|
|
@@ -101,9 +165,9 @@ end
|
|
|
101
165
|
|
|
102
166
|
OpenapiBlocks provides two base classes with distinct responsibilities:
|
|
103
167
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
168
|
+
- OpenapiBlocks::Serializer — defines the model, fields, associations, and serialization logic. Lives in app/serializers/.
|
|
169
|
+
- OpenapiBlocks::Controller — defines API operations, parameters, and responses for documentation. Lives in app/openapi/.
|
|
170
|
+
- OpenapiBlocks::Base — legacy base class that combines both concerns. Still supported.
|
|
107
171
|
|
|
108
172
|
### Recommended: Serializer + Controller
|
|
109
173
|
|
|
@@ -142,7 +206,7 @@ end
|
|
|
142
206
|
```ruby
|
|
143
207
|
# app/openapi/user_openapi.rb
|
|
144
208
|
class UserOpenapi < OpenapiBlocks::Controller
|
|
145
|
-
resource UserSerializer
|
|
209
|
+
resource UserSerializer # links to the serializer — schema is derived from it
|
|
146
210
|
controller UsersController
|
|
147
211
|
|
|
148
212
|
tags "Users"
|
|
@@ -169,6 +233,19 @@ class UserOpenapi < OpenapiBlocks::Controller
|
|
|
169
233
|
end
|
|
170
234
|
```
|
|
171
235
|
|
|
236
|
+
#### How the OpenAPI schema is generated
|
|
237
|
+
|
|
238
|
+
When `resource UserSerializer` is declared in a `Controller`, OpenapiBlocks derives the OpenAPI schema directly from the serializer — not from the model. This guarantees that what is documented is exactly what the API returns.
|
|
239
|
+
|
|
240
|
+
The schema is built from three sources on the serializer:
|
|
241
|
+
|
|
242
|
+
- ActiveRecord columns — read from `db/schema.rb` via the inferred model. Column types are mapped to OpenAPI types automatically.
|
|
243
|
+
- `attribute` declarations — virtual fields not present in the database. Fields declared with `read_only: true` appear in the `User` response schema but are excluded from the `UserInput` request schema.
|
|
244
|
+
- `association` declarations — resolved as `$ref` to the associated schema. Associations declared with `read_only: true` appear in the response but are excluded from `UserInput`.
|
|
245
|
+
- `ignore` declarations — columns excluded from both schemas.
|
|
246
|
+
|
|
247
|
+
The `UserInput` schema (used in POST, PUT and PATCH request bodies) is derived automatically from the `User` schema by removing `id`, `created_at`, `updated_at`, and any field marked `read_only: true`.
|
|
248
|
+
|
|
172
249
|
```ruby
|
|
173
250
|
# app/controllers/users_controller.rb
|
|
174
251
|
def index
|
|
@@ -229,7 +306,7 @@ def show
|
|
|
229
306
|
end
|
|
230
307
|
```
|
|
231
308
|
|
|
232
|
-
Serializer registration is automatic by convention (
|
|
309
|
+
Serializer registration is automatic by convention (UserSerializer -> User). For explicit registration:
|
|
233
310
|
|
|
234
311
|
```ruby
|
|
235
312
|
class AdminUserSerializer < OpenapiBlocks::Serializer
|
|
@@ -243,34 +320,41 @@ If no serializer is found, OpenapiBlocks falls back to default Rails rendering a
|
|
|
243
320
|
|
|
244
321
|
## Serializer
|
|
245
322
|
|
|
246
|
-
The built-in serializer compiles a monolithic extractor method per class at boot time using
|
|
323
|
+
The built-in serializer compiles a monolithic extractor method per class at boot time using class_eval. There are no loops, no lambda indirection, and no runtime branching per object.
|
|
247
324
|
|
|
248
325
|
### Performance (200 records, arm64, Ruby 4.0)
|
|
249
326
|
|
|
250
327
|
| Method | i/s | μs/i | vs serialize |
|
|
251
|
-
|
|
252
|
-
| serialize | 4
|
|
253
|
-
| to_json | 1 444 | 692 | 2.
|
|
254
|
-
| as_json | 1
|
|
255
|
-
| oj+as_json | 1 126 |
|
|
328
|
+
|------------|-------|------|--------------|
|
|
329
|
+
| serialize | 4 504 | 198 | — |
|
|
330
|
+
| to_json | 1 444 | 692 | 2.89x slower |
|
|
331
|
+
| as_json | 1 179 | 453 | 2.81x slower |
|
|
332
|
+
| oj+as_json | 1 126 | 572 | 2.89x slower |
|
|
333
|
+
| AMS | 559 | 178 | 9.02x slower |
|
|
334
|
+
|
|
335
|
+
Scaling is linear — the 2.81x advantage over as_json holds from 10 to 5000 records.
|
|
336
|
+
|
|
337
|
+
### Memory Allocation
|
|
256
338
|
|
|
257
|
-
|
|
339
|
+
OpenapiBlocks: 20MB / 225k objects — fastest and lowest memory
|
|
340
|
+
as_json: 116MB / 1.2M objects — 2.81x slower, 5.6x more memory
|
|
341
|
+
AMS: 260MB / 2.7M objects — 9x slower, 13x more memory
|
|
258
342
|
|
|
259
343
|
### Virtual attributes and method resolution
|
|
260
344
|
|
|
261
|
-
| Declared with
|
|
262
|
-
|
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
| column in db
|
|
345
|
+
| Declared with | Method in serializer? | Calls |
|
|
346
|
+
| -------------------- | --------------------- | ------------------------------------- |
|
|
347
|
+
| attribute :full_name | yes | serializer_instance.full_name |
|
|
348
|
+
| attribute :full_name | no | object.full_name (delegated to model) |
|
|
349
|
+
| column in db | — | object.attribute (direct) |
|
|
266
350
|
|
|
267
351
|
### Association serializer resolution
|
|
268
352
|
|
|
269
353
|
For each association, the serializer resolves the serializer class in this order:
|
|
270
354
|
|
|
271
|
-
1.
|
|
272
|
-
2.
|
|
273
|
-
3. Fallback — calls
|
|
355
|
+
1. PostSerializer — has serialize, used directly.
|
|
356
|
+
2. PostOpenapi — is a Controller, delegates to its resource.
|
|
357
|
+
3. Fallback — calls as_json on the association value.
|
|
274
358
|
|
|
275
359
|
---
|
|
276
360
|
|
|
@@ -289,14 +373,14 @@ end
|
|
|
289
373
|
|
|
290
374
|
OpenapiBlocks generates:
|
|
291
375
|
|
|
292
|
-
-
|
|
293
|
-
-
|
|
294
|
-
-
|
|
295
|
-
-
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
- All paths from
|
|
376
|
+
- User schema from db/schema.rb columns and types
|
|
377
|
+
- UserInput schema for POST, PUT and PATCH request bodies (without id, created_at, updated_at and read_only fields)
|
|
378
|
+
- required fields from presence: true validations
|
|
379
|
+
- minLength, maxLength from length validations
|
|
380
|
+
- minimum, maximum from numericality validations
|
|
381
|
+
- enum from inclusion validations
|
|
382
|
+
- format: "email" from format validations
|
|
383
|
+
- All paths from config/routes.rb
|
|
300
384
|
|
|
301
385
|
---
|
|
302
386
|
|
|
@@ -339,10 +423,10 @@ association :posts, type: :array, read_only: true # excluded from UserInput (re
|
|
|
339
423
|
|
|
340
424
|
Virtual attributes are fields that exist in the API response but not in the database.
|
|
341
425
|
|
|
342
|
-
| Option
|
|
343
|
-
|
|
|
344
|
-
|
|
|
345
|
-
|
|
|
426
|
+
| Option | Description | Appears in User | Appears in UserInput |
|
|
427
|
+
| ---------------- | -------------------------------------- | :-------------: | :------------------: |
|
|
428
|
+
| read_only: true | Calculated or system-generated fields | YES | NO |
|
|
429
|
+
| read_only: false | Fields the client can send and receive | YES | YES |
|
|
346
430
|
|
|
347
431
|
```ruby
|
|
348
432
|
attribute :full_name, type: :string, read_only: true # response only
|
|
@@ -354,19 +438,19 @@ attribute :nickname, type: :string # request and response
|
|
|
354
438
|
|
|
355
439
|
## Type Mapping
|
|
356
440
|
|
|
357
|
-
| ActiveRecord type | OpenAPI type
|
|
358
|
-
| ----------------- |
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
|
368
|
-
|
|
|
369
|
-
|
|
|
441
|
+
| ActiveRecord type | OpenAPI type |
|
|
442
|
+
| ----------------- | ------------------ |
|
|
443
|
+
| integer | integer / int32 |
|
|
444
|
+
| bigint | integer / int64 |
|
|
445
|
+
| float | number / float |
|
|
446
|
+
| decimal | number / double |
|
|
447
|
+
| string | string |
|
|
448
|
+
| text | string |
|
|
449
|
+
| boolean | boolean |
|
|
450
|
+
| date | string / date |
|
|
451
|
+
| datetime | string / date-time |
|
|
452
|
+
| uuid | string / uuid |
|
|
453
|
+
| json / jsonb | object |
|
|
370
454
|
|
|
371
455
|
---
|
|
372
456
|
|
|
@@ -382,7 +466,7 @@ config/routes.rb
|
|
|
382
466
|
db/schema.rb
|
|
383
467
|
```
|
|
384
468
|
|
|
385
|
-
The spec is automatically regenerated on the next request to
|
|
469
|
+
The spec is automatically regenerated on the next request to /docs/openapi.json whenever any of these files change. No server restart needed.
|
|
386
470
|
|
|
387
471
|
---
|
|
388
472
|
|
|
@@ -395,4 +479,4 @@ The spec is automatically regenerated on the next request to `/docs/openapi.json
|
|
|
395
479
|
|
|
396
480
|
## License
|
|
397
481
|
|
|
398
|
-
|
|
482
|
+
MIT (LICENSE.txt)
|
data/README.pt-BR.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# OpenapiBlocks
|
|
2
2
|
|
|
3
|
-
OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus models ActiveRecord, validações ActiveModel e rotas do Rails — inspirada no
|
|
3
|
+
OpenapiBlocks é uma gem Rails que gera automaticamente documentação OpenAPI 3.0/3.1 a partir dos seus models ActiveRecord, validações ActiveModel e rotas do Rails — inspirada no ActiveModel::Serializer (https://github.com/rails-api/active_model_serializers).
|
|
4
4
|
|
|
5
|
-
English version:
|
|
5
|
+
English version: README.md
|
|
6
6
|
|
|
7
|
-
Sem anotações manuais. Sem DSL nos controllers. Basta declarar o que expor e a spec é gerada automaticamente. Inclui um serializer de alta performance — ~3.6× mais rápido que
|
|
7
|
+
Sem anotações manuais. Sem DSL nos controllers. Basta declarar o que expor e a spec é gerada automaticamente. Inclui um serializer de alta performance — ~3.6× mais rápido que as_json com escalabilidade linear de 10 a 5000 registros.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Instalação
|
|
12
12
|
|
|
13
|
-
Adicione ao seu
|
|
13
|
+
Adicione ao seu Gemfile:
|
|
14
14
|
|
|
15
15
|
```ruby
|
|
16
16
|
gem "openapi_blocks"
|
|
@@ -24,6 +24,70 @@ bundle install
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
+
## Generators
|
|
28
|
+
|
|
29
|
+
O OpenapiBlocks oferece três generators para começar rapidamente.
|
|
30
|
+
|
|
31
|
+
### Install
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
rails generate openapi_blocks:install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Cria `config/initializers/openapi_blocks.rb` com todas as opções disponíveis comentadas, e monta o engine no `config/routes.rb`:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
mount OpenapiBlocks::Engine => "/docs"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Openapi
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
rails generate openapi_blocks:openapi User
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Cria `app/openapi/user_openapi.rb` com todas as opções de DSL disponíveis comentadas:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# app/openapi/user_openapi.rb
|
|
53
|
+
class UserOpenapi < OpenapiBlocks::Controller
|
|
54
|
+
# resource UserSerializer
|
|
55
|
+
# controller UsersController
|
|
56
|
+
|
|
57
|
+
# tags "Usuários"
|
|
58
|
+
|
|
59
|
+
# operation :index do
|
|
60
|
+
# summary "Lista todos os usuários"
|
|
61
|
+
# response 200, description: "Lista de usuários", schema: { type: :array, items: :User }
|
|
62
|
+
# end
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Serializer
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
rails generate openapi_blocks:serializer User
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Cria `app/serializers/user_serializer.rb` com todas as opções de DSL disponíveis comentadas:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
# app/serializers/user_serializer.rb
|
|
76
|
+
class UserSerializer < OpenapiBlocks::Serializer
|
|
77
|
+
# ignore :password_digest, :reset_password_token
|
|
78
|
+
|
|
79
|
+
# association :posts, type: :array, read_only: true
|
|
80
|
+
# association :company
|
|
81
|
+
|
|
82
|
+
# attribute :full_name, type: :string, read_only: true
|
|
83
|
+
# def full_name
|
|
84
|
+
# "#{object.first_name} #{object.last_name}"
|
|
85
|
+
# end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
27
91
|
## Configuração
|
|
28
92
|
|
|
29
93
|
### 1. Monte o Engine
|
|
@@ -48,7 +112,7 @@ GET /docs/openapi.yaml -> Spec OpenAPI em YAML
|
|
|
48
112
|
|
|
49
113
|
### 2. Configure o initializer
|
|
50
114
|
|
|
51
|
-
|
|
115
|
+
OpenapiBlocks.configure é obrigatório. A gem lança OpenapiBlocks::Error na primeira requisição se nunca foi chamado ou se info.title / info.version estiverem em branco.
|
|
52
116
|
|
|
53
117
|
```ruby
|
|
54
118
|
# config/initializers/openapi_blocks.rb
|
|
@@ -99,11 +163,11 @@ end
|
|
|
99
163
|
|
|
100
164
|
## Uso
|
|
101
165
|
|
|
102
|
-
OpenapiBlocks oferece duas classes base com responsabilidades distintas:
|
|
166
|
+
O OpenapiBlocks oferece duas classes base com responsabilidades distintas:
|
|
103
167
|
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
168
|
+
- OpenapiBlocks::Serializer — define o model, campos, associações e lógica de serialização. Fica em app/serializers/.
|
|
169
|
+
- OpenapiBlocks::Controller — define operações, parâmetros e respostas para documentação. Fica em app/openapi/.
|
|
170
|
+
- OpenapiBlocks::Base — classe base legada que combina ambas as responsabilidades. Ainda suportada.
|
|
107
171
|
|
|
108
172
|
### Recomendado: Serializer + Controller
|
|
109
173
|
|
|
@@ -142,7 +206,7 @@ end
|
|
|
142
206
|
```ruby
|
|
143
207
|
# app/openapi/user_openapi.rb
|
|
144
208
|
class UserOpenapi < OpenapiBlocks::Controller
|
|
145
|
-
resource UserSerializer
|
|
209
|
+
resource UserSerializer # vincula ao serializer — o schema é derivado dele
|
|
146
210
|
controller UsersController
|
|
147
211
|
|
|
148
212
|
tags "Usuários"
|
|
@@ -169,6 +233,19 @@ class UserOpenapi < OpenapiBlocks::Controller
|
|
|
169
233
|
end
|
|
170
234
|
```
|
|
171
235
|
|
|
236
|
+
#### Como o schema OpenAPI é gerado
|
|
237
|
+
|
|
238
|
+
Quando `resource UserSerializer` é declarado em um `Controller`, o OpenapiBlocks deriva o schema OpenAPI diretamente do serializer — não do model. Isso garante que o que está documentado é exatamente o que a API retorna.
|
|
239
|
+
|
|
240
|
+
O schema é construído a partir de três fontes no serializer:
|
|
241
|
+
|
|
242
|
+
- Colunas do ActiveRecord — lidas do `db/schema.rb` via o model inferido. Os tipos das colunas são mapeados para tipos OpenAPI automaticamente.
|
|
243
|
+
- Declarações `attribute` — campos virtuais que não existem no banco. Campos declarados com `read_only: true` aparecem no schema de resposta `User` mas são excluídos do schema de requisição `UserInput`.
|
|
244
|
+
- Declarações `association` — resolvidas como `$ref` para o schema associado. Associações com `read_only: true` aparecem na resposta mas são excluídas do `UserInput`.
|
|
245
|
+
- Declarações `ignore` — colunas excluídas de ambos os schemas.
|
|
246
|
+
|
|
247
|
+
O schema `UserInput` (usado nos request bodies de POST, PUT e PATCH) é derivado automaticamente do schema `User` removendo `id`, `created_at`, `updated_at` e qualquer campo marcado com `read_only: true`.
|
|
248
|
+
|
|
172
249
|
```ruby
|
|
173
250
|
# app/controllers/users_controller.rb
|
|
174
251
|
def index
|
|
@@ -229,7 +306,7 @@ def show
|
|
|
229
306
|
end
|
|
230
307
|
```
|
|
231
308
|
|
|
232
|
-
O registro do serializer é automático por convenção (
|
|
309
|
+
O registro do serializer é automático por convenção (UserSerializer -> User). Para registro explícito:
|
|
233
310
|
|
|
234
311
|
```ruby
|
|
235
312
|
class AdminUserSerializer < OpenapiBlocks::Serializer
|
|
@@ -243,34 +320,41 @@ Se nenhum serializer for encontrado, o OpenapiBlocks usa o comportamento padrão
|
|
|
243
320
|
|
|
244
321
|
## Serializer
|
|
245
322
|
|
|
246
|
-
O serializer compila um método extrator monolítico por classe no boot usando
|
|
323
|
+
O serializer compila um método extrator monolítico por classe no boot usando class_eval. Sem loops, sem indireção via lambda e sem branching por objeto em tempo de execução.
|
|
247
324
|
|
|
248
325
|
### Performance (200 registros, arm64, Ruby 4.0)
|
|
249
326
|
|
|
250
|
-
|
|
|
327
|
+
| Method | i/s | μs/i | vs serialize |
|
|
251
328
|
|------------|-------|------|--------------|
|
|
252
|
-
| serialize | 4
|
|
253
|
-
| to_json | 1 444 | 692 | 2.
|
|
254
|
-
| as_json | 1
|
|
255
|
-
| oj+as_json | 1 126 |
|
|
329
|
+
| serialize | 4 504 | 198 | — |
|
|
330
|
+
| to_json | 1 444 | 692 | 2.89x mais lento |
|
|
331
|
+
| as_json | 1 179 | 453 | 2.81x mais lento |
|
|
332
|
+
| oj+as_json | 1 126 | 572 | 2.89x mais lento |
|
|
333
|
+
| AMS | 559 | 178 | 9.02x mais lento |
|
|
334
|
+
|
|
335
|
+
A escalabilidade é linear — a vantagem de 2.81× sobre o as_json se mantém de 10 a 5000 registros.
|
|
336
|
+
|
|
337
|
+
### Memória alocada
|
|
256
338
|
|
|
257
|
-
|
|
339
|
+
OpenapiBlocks: 20MB / 225k objetos — mais rápido e com menor consumo de memória
|
|
340
|
+
as_json: 116MB / 1,2M objetos — 2,81x mais lento, 5,6x mais memória
|
|
341
|
+
AMS: 260MB / 2,7M objetos — 9x mais lento, 13x mais memória
|
|
258
342
|
|
|
259
343
|
### Atributos virtuais e resolução de métodos
|
|
260
344
|
|
|
261
|
-
| Declarado com
|
|
262
|
-
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
| coluna no banco
|
|
345
|
+
| Declarado com | Método no serializer? | Chama |
|
|
346
|
+
| -------------------- | --------------------- | ------------------------------------ |
|
|
347
|
+
| attribute :full_name | sim | serializer_instance.full_name |
|
|
348
|
+
| attribute :full_name | não | object.full_name (delegado ao model) |
|
|
349
|
+
| coluna no banco | — | object.attribute (direto) |
|
|
266
350
|
|
|
267
351
|
### Resolução do serializer de associações
|
|
268
352
|
|
|
269
353
|
Para cada associação, o serializer resolve a classe na seguinte ordem:
|
|
270
354
|
|
|
271
|
-
1.
|
|
272
|
-
2.
|
|
273
|
-
3. Fallback — chama
|
|
355
|
+
1. PostSerializer — tem serialize, usado diretamente.
|
|
356
|
+
2. PostOpenapi — é um Controller, delega para o \_resource.
|
|
357
|
+
3. Fallback — chama as_json no valor da associação.
|
|
274
358
|
|
|
275
359
|
---
|
|
276
360
|
|
|
@@ -289,14 +373,14 @@ end
|
|
|
289
373
|
|
|
290
374
|
O OpenapiBlocks gera:
|
|
291
375
|
|
|
292
|
-
- Schema
|
|
293
|
-
- Schema
|
|
294
|
-
- Campos
|
|
295
|
-
-
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
-
|
|
299
|
-
- Todos os paths a partir do
|
|
376
|
+
- Schema User a partir das colunas e tipos do db/schema.rb
|
|
377
|
+
- Schema UserInput para os request bodies de POST, PUT e PATCH (sem id, created_at, updated_at e campos read_only)
|
|
378
|
+
- Campos required a partir das validações presence: true
|
|
379
|
+
- minLength, maxLength a partir das validações length
|
|
380
|
+
- minimum, maximum a partir das validações numericality
|
|
381
|
+
- enum a partir das validações inclusion
|
|
382
|
+
- format: "email" a partir das validações de formato
|
|
383
|
+
- Todos os paths a partir do config/routes.rb
|
|
300
384
|
|
|
301
385
|
---
|
|
302
386
|
|
|
@@ -339,10 +423,10 @@ association :posts, type: :array, read_only: true # excluído do UserInput (som
|
|
|
339
423
|
|
|
340
424
|
Atributos virtuais são campos que existem na resposta da API mas não no banco de dados.
|
|
341
425
|
|
|
342
|
-
| Opção
|
|
343
|
-
|
|
344
|
-
|
|
|
345
|
-
|
|
|
426
|
+
| Opção | Descrição | Aparece em User | Aparece em UserInput |
|
|
427
|
+
| ---------------- | ------------------------------------------ | :-------------: | :------------------: |
|
|
428
|
+
| read_only: true | Campos calculados ou gerados pelo sistema | SIM | NÃO |
|
|
429
|
+
| read_only: false | Campos que o cliente pode enviar e receber | SIM | SIM |
|
|
346
430
|
|
|
347
431
|
```ruby
|
|
348
432
|
attribute :full_name, type: :string, read_only: true # somente resposta
|
|
@@ -354,19 +438,19 @@ attribute :nickname, type: :string # requisição e respos
|
|
|
354
438
|
|
|
355
439
|
## Mapeamento de Tipos
|
|
356
440
|
|
|
357
|
-
| Tipo ActiveRecord | Tipo OpenAPI
|
|
358
|
-
|
|
359
|
-
|
|
|
360
|
-
|
|
|
361
|
-
|
|
|
362
|
-
|
|
|
363
|
-
|
|
|
364
|
-
|
|
|
365
|
-
|
|
|
366
|
-
|
|
|
367
|
-
|
|
|
368
|
-
|
|
|
369
|
-
|
|
|
441
|
+
| Tipo ActiveRecord | Tipo OpenAPI |
|
|
442
|
+
| ----------------- | ------------------ |
|
|
443
|
+
| integer | integer / int32 |
|
|
444
|
+
| bigint | integer / int64 |
|
|
445
|
+
| float | number / float |
|
|
446
|
+
| decimal | number / double |
|
|
447
|
+
| string | string |
|
|
448
|
+
| text | string |
|
|
449
|
+
| boolean | boolean |
|
|
450
|
+
| date | string / date |
|
|
451
|
+
| datetime | string / date-time |
|
|
452
|
+
| uuid | string / uuid |
|
|
453
|
+
| json / jsonb | object |
|
|
370
454
|
|
|
371
455
|
---
|
|
372
456
|
|
|
@@ -382,7 +466,7 @@ config/routes.rb
|
|
|
382
466
|
db/schema.rb
|
|
383
467
|
```
|
|
384
468
|
|
|
385
|
-
A spec é regenerada automaticamente na próxima requisição a
|
|
469
|
+
A spec é regenerada automaticamente na próxima requisição a /docs/openapi.json sempre que algum desses arquivos for alterado. Sem precisar reiniciar o servidor.
|
|
386
470
|
|
|
387
471
|
---
|
|
388
472
|
|
|
@@ -395,4 +479,4 @@ A spec é regenerada automaticamente na próxima requisição a `/docs/openapi.j
|
|
|
395
479
|
|
|
396
480
|
## Licença
|
|
397
481
|
|
|
398
|
-
|
|
482
|
+
MIT (LICENSE.txt)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenapiBlocks
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base # rubocop:disable Style/Documentation
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates an OpenapiBlocks initializer and mounts the engine in routes.rb"
|
|
9
|
+
|
|
10
|
+
def create_initializer
|
|
11
|
+
template "initializer.rb.tt", "config/initializers/openapi_blocks.rb"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def mount_engine
|
|
15
|
+
route 'mount OpenapiBlocks::Engine => "/docs"'
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
OpenapiBlocks.configure do |config|
|
|
4
|
+
# config.openapi_version = "3.1.0" # required — "3.0.3" or "3.1.0"
|
|
5
|
+
|
|
6
|
+
# config.auto_serialize = true # default is false
|
|
7
|
+
|
|
8
|
+
config.info do
|
|
9
|
+
title "My API" # required
|
|
10
|
+
version "1.0.0" # required
|
|
11
|
+
description "API documentation generated automatically"
|
|
12
|
+
|
|
13
|
+
# contact do
|
|
14
|
+
# name "My Team"
|
|
15
|
+
# email "api@mycompany.com"
|
|
16
|
+
# url "https://mycompany.com"
|
|
17
|
+
# end
|
|
18
|
+
|
|
19
|
+
# license do
|
|
20
|
+
# name "MIT"
|
|
21
|
+
# url "https://opensource.org/licenses/MIT"
|
|
22
|
+
# end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# config.servers do
|
|
26
|
+
# server do
|
|
27
|
+
# url "http://localhost:3000"
|
|
28
|
+
# description "Development"
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
|
|
32
|
+
# config.security do
|
|
33
|
+
# bearer_token format: "JWT" # Authorization: Bearer <token>
|
|
34
|
+
# api_key name: "X-API-Key", in: :header # X-API-Key: <key>
|
|
35
|
+
# end
|
|
36
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenapiBlocks
|
|
4
|
+
module Generators
|
|
5
|
+
class OpenapiGenerator < Rails::Generators::NamedBase # rubocop:disable Style/Documentation
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates an OpenapiBlocks Controller class in app/openapi/"
|
|
9
|
+
|
|
10
|
+
def create_openapi_file
|
|
11
|
+
template "openapi.rb.tt", "app/openapi/#{file_name}_openapi.rb"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= class_name %>Openapi < OpenapiBlocks::Controller
|
|
4
|
+
# resource <%= class_name %>Serializer
|
|
5
|
+
# controller <%= class_name %>Controller
|
|
6
|
+
|
|
7
|
+
# tags "<%= class_name.pluralize %>"
|
|
8
|
+
|
|
9
|
+
# operation :index do
|
|
10
|
+
# summary "List all <%= class_name.pluralize.downcase %>"
|
|
11
|
+
# description "Returns a paginated list of <%= class_name.pluralize.downcase %>"
|
|
12
|
+
#
|
|
13
|
+
# parameter :page, in: :query, type: :integer, description: "Page number"
|
|
14
|
+
# parameter :per_page, in: :query, type: :integer, description: "Items per page"
|
|
15
|
+
#
|
|
16
|
+
# response 200, description: "List of <%= class_name.pluralize.downcase %>", schema: { type: :array, items: :<%= class_name %> }
|
|
17
|
+
# response 401, description: "Unauthorized"
|
|
18
|
+
# end
|
|
19
|
+
|
|
20
|
+
# operation :show do
|
|
21
|
+
# summary "Get a <%= class_name.downcase %>"
|
|
22
|
+
#
|
|
23
|
+
# response 200, description: "<%= class_name %> found", schema: :<%= class_name %>
|
|
24
|
+
# response 404, description: "<%= class_name %> not found"
|
|
25
|
+
# end
|
|
26
|
+
|
|
27
|
+
# operation :create do
|
|
28
|
+
# summary "Create a <%= class_name.downcase %>"
|
|
29
|
+
#
|
|
30
|
+
# response 201, description: "<%= class_name %> created", schema: :<%= class_name %>
|
|
31
|
+
# response 422, description: "Invalid data"
|
|
32
|
+
# end
|
|
33
|
+
|
|
34
|
+
# operation :update do
|
|
35
|
+
# summary "Update a <%= class_name.downcase %>"
|
|
36
|
+
#
|
|
37
|
+
# response 200, description: "<%= class_name %> updated", schema: :<%= class_name %>
|
|
38
|
+
# response 404, description: "<%= class_name %> not found"
|
|
39
|
+
# response 422, description: "Invalid data"
|
|
40
|
+
# end
|
|
41
|
+
|
|
42
|
+
# operation :destroy do
|
|
43
|
+
# summary "Delete a <%= class_name.downcase %>"
|
|
44
|
+
#
|
|
45
|
+
# response 200, description: "<%= class_name %> deleted"
|
|
46
|
+
# response 404, description: "<%= class_name %> not found"
|
|
47
|
+
# end
|
|
48
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OpenapiBlocks
|
|
4
|
+
module Generators
|
|
5
|
+
class SerializerGenerator < Rails::Generators::NamedBase # rubocop:disable Style/Documentation
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates an OpenapiBlocks Serializer class in app/serializers/"
|
|
9
|
+
|
|
10
|
+
def create_serializer_file
|
|
11
|
+
template "serializer.rb.tt", "app/serializers/#{file_name}_serializer.rb"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class <%= class_name %>Serializer < OpenapiBlocks::Serializer
|
|
4
|
+
# model <%= class_name %> is inferred automatically from the class name
|
|
5
|
+
|
|
6
|
+
# ignore :password_digest, :reset_password_token
|
|
7
|
+
|
|
8
|
+
# association :posts, type: :array, read_only: true
|
|
9
|
+
# association :company
|
|
10
|
+
|
|
11
|
+
# attribute :full_name, type: :string, read_only: true
|
|
12
|
+
# def full_name
|
|
13
|
+
# "#{object.first_name} #{object.last_name}"
|
|
14
|
+
# end
|
|
15
|
+
end
|
|
@@ -4,6 +4,12 @@ require "rails"
|
|
|
4
4
|
|
|
5
5
|
module OpenapiBlocks
|
|
6
6
|
class Railtie < Rails::Railtie # rubocop:disable Style/Documentation
|
|
7
|
+
generators do
|
|
8
|
+
require "generators/openapi_blocks/install/install_generator"
|
|
9
|
+
require "generators/openapi_blocks/openapi/openapi_generator"
|
|
10
|
+
require "generators/openapi_blocks/serializer/serializer_generator"
|
|
11
|
+
end
|
|
12
|
+
|
|
7
13
|
initializer "openapi_blocks.autoload", before: :set_autoload_paths do |app|
|
|
8
14
|
app.config.eager_load_paths << app.root.join("app/openapi")
|
|
9
15
|
app.config.eager_load_paths << app.root.join("app/serializers")
|
|
@@ -30,17 +30,28 @@ module OpenapiBlocks
|
|
|
30
30
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
|
-
def build_compiled_extractor # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
33
|
+
def build_compiled_extractor # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
34
34
|
classified = classify_fields
|
|
35
|
+
classified[:association].each { |field| build_assoc_method(field) }
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
%("#{f}" => _serialize_assoc_#{f}(object))
|
|
37
|
+
all_fields = classified.values.flatten
|
|
38
|
+
all_fields.each do |f|
|
|
39
|
+
const_name = "KEY_#{f.upcase}"
|
|
40
|
+
const_set(const_name, f.freeze) unless const_defined?(const_name)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
classified[:
|
|
43
|
+
model_lines = classified[:model].map do |f|
|
|
44
|
+
%(#{name}::KEY_#{f.upcase} => object.#{f})
|
|
45
|
+
end
|
|
46
|
+
delegated_lines = classified[:delegated].map do |f|
|
|
47
|
+
%(#{name}::KEY_#{f.upcase} => object.#{f})
|
|
48
|
+
end
|
|
49
|
+
virtual_lines = classified[:virtual].map do |f|
|
|
50
|
+
%(#{name}::KEY_#{f.upcase} => inst.#{f})
|
|
51
|
+
end
|
|
52
|
+
assoc_lines = classified[:association].map do |f|
|
|
53
|
+
%(#{name}::KEY_#{f.upcase} => _serialize_assoc_#{f}(object))
|
|
54
|
+
end
|
|
44
55
|
|
|
45
56
|
all_lines = (model_lines + delegated_lines + virtual_lines + assoc_lines).join(",\n ")
|
|
46
57
|
|
|
@@ -86,7 +97,7 @@ module OpenapiBlocks
|
|
|
86
97
|
def self._serialize_assoc_#{field}(object)
|
|
87
98
|
val = object.public_send(:#{assoc_name})
|
|
88
99
|
return nil if val.nil?
|
|
89
|
-
|
|
100
|
+
#{serializer}.serialize(val)
|
|
90
101
|
end
|
|
91
102
|
RUBY
|
|
92
103
|
else
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openapi_blocks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Caio Santos
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-06-03 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: oj
|
|
@@ -139,6 +140,12 @@ files:
|
|
|
139
140
|
- Rakefile
|
|
140
141
|
- app/controllers/openapi_blocks/spec_controller.rb
|
|
141
142
|
- config/routes.rb
|
|
143
|
+
- lib/generators/openapi_blocks/install/install_generator.rb
|
|
144
|
+
- lib/generators/openapi_blocks/install/templates/initializer.rb.tt
|
|
145
|
+
- lib/generators/openapi_blocks/openapi/openapi_generator.rb
|
|
146
|
+
- lib/generators/openapi_blocks/openapi/templates/openapi.rb.tt
|
|
147
|
+
- lib/generators/openapi_blocks/serializer/serializer_generator.rb
|
|
148
|
+
- lib/generators/openapi_blocks/serializer/templates/serializer.rb.tt
|
|
142
149
|
- lib/openapi_blocks.rb
|
|
143
150
|
- lib/openapi_blocks/auto_serialize.rb
|
|
144
151
|
- lib/openapi_blocks/base.rb
|
|
@@ -180,6 +187,7 @@ metadata:
|
|
|
180
187
|
source_code_uri: https://github.com/evotechbuilder/openapi_blocks
|
|
181
188
|
changelog_uri: https://github.com/evotechbuilder/openapi_blocks/blob/main/CHANGELOG.md
|
|
182
189
|
rubygems_mfa_required: 'true'
|
|
190
|
+
post_install_message:
|
|
183
191
|
rdoc_options: []
|
|
184
192
|
require_paths:
|
|
185
193
|
- lib
|
|
@@ -194,7 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
194
202
|
- !ruby/object:Gem::Version
|
|
195
203
|
version: '0'
|
|
196
204
|
requirements: []
|
|
197
|
-
rubygems_version: 4.
|
|
205
|
+
rubygems_version: 3.4.1
|
|
206
|
+
signing_key:
|
|
198
207
|
specification_version: 4
|
|
199
208
|
summary: OpenAPI 3.0/3.1 documentation and high-performance serializer for Rails
|
|
200
209
|
test_files: []
|