docit 0.3.1 → 0.4.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/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
- data/CHANGELOG.md +23 -1
- data/CONTRIBUTING.md +1 -1
- data/README.md +26 -390
- data/lib/docit/ai/autodoc_runner.rb +25 -24
- data/lib/docit/ai/tag_injector.rb +1 -1
- data/lib/docit/configuration.rb +33 -0
- data/lib/docit/doc_file.rb +1 -1
- data/lib/docit/dsl.rb +6 -3
- data/lib/docit/operation.rb +7 -2
- data/lib/docit/route_inspector.rb +1 -1
- data/lib/docit/schema_generator.rb +24 -5
- data/lib/docit/version.rb +1 -1
- data/lib/generators/docit/install/install_generator.rb +3 -3
- data/lib/tasks/docit.rake +1 -1
- metadata +4 -6
- data/docs/images/scalar_image.png +0 -0
- data/docs/images/swagger_image.png +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 39589c6800b65d7a0ad55701378b345f18277735df3511cce965bc889035e74f
|
|
4
|
+
data.tar.gz: 91c392bded5bbd0897222859feab4d68e8c0d3064d4054e6b75509a325ced2d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1ea253c903e6a90eb3754ed9f4a586adcc7339c831d9623401cc4bb53256359c81e069bba4067a12379da350fbf354b50bfd14420ae0aa75c3841c74942ae5f2
|
|
7
|
+
data.tar.gz: 8441b41ae22a25f1bd29514fbdcb425b4bbd56b591da6904df0c9ad070a7ac830b1eb9338783a8c751d8f648db4826d69b7755a0f42cd320baaf8e3ebeb7c628
|
|
@@ -17,7 +17,7 @@ Explain the problem this feature would solve or the workflow it would improve.
|
|
|
17
17
|
Describe how you'd like it to work, including example DSL usage if applicable:
|
|
18
18
|
|
|
19
19
|
```ruby
|
|
20
|
-
|
|
20
|
+
doc_for :index do
|
|
21
21
|
# your proposed syntax here
|
|
22
22
|
end
|
|
23
23
|
```
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-04-18
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `operation_id` DSL method: set a custom `operationId` per endpoint for cleaner SDK codegen
|
|
7
|
+
- Auto-generated `operationId` for every endpoint (e.g., `index_users`, `login_auth`) when not explicitly set
|
|
8
|
+
- `config.license` option: add license info (`name`, `url`) to the OpenAPI spec
|
|
9
|
+
- `config.contact` option: add contact info (`name`, `email`, `url`) to the OpenAPI spec
|
|
10
|
+
- `config.terms_of_service` option: add terms of service URL to the OpenAPI spec
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Renamed `swagger_doc` DSL to `doc_for` (`swagger_doc` still works as a backward-compatible alias)
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- `TagInjector` no longer crashes when `initializer_path` is nil
|
|
17
|
+
- `docit:autodoc` rake task: removed broken `--dry-run` CLI flag (use `DRY_RUN=1` env var instead)
|
|
18
|
+
- Fixed dummy app `auth_docs.rb` summary and request body to match integration test expectations
|
|
19
|
+
|
|
20
|
+
## [0.3.1] - 2026-04-17
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- Fixed gem packaging: `doc_block_validator.rb` was missing from the published 0.3.0 gem, causing `LoadError` on require
|
|
24
|
+
|
|
3
25
|
## [0.3.0] - 2026-04-16
|
|
4
26
|
|
|
5
27
|
### Added
|
|
@@ -51,7 +73,7 @@
|
|
|
51
73
|
## [0.1.0] - 2026-04-08
|
|
52
74
|
|
|
53
75
|
- Initial release
|
|
54
|
-
- DSL: `
|
|
76
|
+
- DSL: `doc_for` macro for inline controller documentation
|
|
55
77
|
- DSL: `use_docs` + `Docit::DocFile` for separate doc files
|
|
56
78
|
- Builders: request body, response, and parameter builders with nested object/array support
|
|
57
79
|
- Schema `$ref` components via `Docit.define_schema`
|
data/CONTRIBUTING.md
CHANGED
|
@@ -55,7 +55,7 @@ bundle exec rspec spec/docit/v2_features_spec.rb:30
|
|
|
55
55
|
lib/docit.rb # Entry point, configuration, schema registry
|
|
56
56
|
lib/docit/configuration.rb # Config class (title, auth, tags)
|
|
57
57
|
lib/docit/registry.rb # Global operation store
|
|
58
|
-
lib/docit/dsl.rb #
|
|
58
|
+
lib/docit/dsl.rb # doc_for macro
|
|
59
59
|
lib/docit/operation.rb # Single endpoint documentation
|
|
60
60
|
lib/docit/builders/ # DSL builders (response, request_body, parameter)
|
|
61
61
|
lib/docit/schema_definition.rb # Reusable $ref schema definitions
|
data/README.md
CHANGED
|
@@ -11,44 +11,7 @@ Decorator-style API documentation for Ruby on Rails. Write OpenAPI 3.0.3 docs wi
|
|
|
11
11
|
### Swagger
|
|
12
12
|

|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- Getting started
|
|
17
|
-
- [Installation](#installation)
|
|
18
|
-
- [Configuration](#configuration)
|
|
19
|
-
- [Usage](#usage)
|
|
20
|
-
- Documentation styles
|
|
21
|
-
- [Style 1: Inline (simple APIs)](#style-1-inline-simple-apis)
|
|
22
|
-
- [Style 2: Separate doc files (recommended for larger APIs)](#style-2-separate-doc-files-recommended-for-larger-apis)
|
|
23
|
-
- Endpoint DSL reference
|
|
24
|
-
- [Endpoint documentation DSL](#endpoint-documentation-dsl)
|
|
25
|
-
- [Request bodies](#request-bodies)
|
|
26
|
-
- [Path parameters](#path-parameters)
|
|
27
|
-
- [Enums](#enums)
|
|
28
|
-
- [Security](#security)
|
|
29
|
-
- [Deprecated endpoints](#deprecated-endpoints)
|
|
30
|
-
- [Nested objects and arrays](#nested-objects-and-arrays)
|
|
31
|
-
- [Response examples](#response-examples)
|
|
32
|
-
- [Shared schemas (`$ref`)](#shared-schemas-ref)
|
|
33
|
-
- [File uploads](#file-uploads)
|
|
34
|
-
- AI documentation
|
|
35
|
-
- [AI Automatic Documentation](#ai-automatic-documentation)
|
|
36
|
-
- [Quick start (included in install)](#quick-start-included-in-install)
|
|
37
|
-
- [Standalone commands](#standalone-commands)
|
|
38
|
-
- [Supported providers](#supported-providers)
|
|
39
|
-
- [What the AI generates](#what-the-ai-generates)
|
|
40
|
-
- Runtime and development
|
|
41
|
-
- [Documentation UIs](#documentation-uis)
|
|
42
|
-
- [How it works](#how-it-works)
|
|
43
|
-
- [Mounting at a different path](#mounting-at-a-different-path)
|
|
44
|
-
- [JSON spec only](#json-spec-only)
|
|
45
|
-
- [Development](#development)
|
|
46
|
-
- [Contributing](#contributing)
|
|
47
|
-
- [License](#license)
|
|
48
|
-
- Project docs
|
|
49
|
-
- [CHANGELOG](CHANGELOG.md)
|
|
50
|
-
- [CONTRIBUTING](CONTRIBUTING.md)
|
|
51
|
-
- [CODE OF CONDUCT](CODE_OF_CONDUCT.md)
|
|
14
|
+
> **Full documentation:** [docitruby.dev/docs](https://docitruby.dev/docs)
|
|
52
15
|
|
|
53
16
|
## Installation
|
|
54
17
|
|
|
@@ -76,8 +39,6 @@ The install generator does everything in one step:
|
|
|
76
39
|
|
|
77
40
|
Visit `/api-docs` to see your interactive API documentation (Scalar by default, Swagger UI also available at `/api-docs/swagger`).
|
|
78
41
|
|
|
79
|
-
If you choose AI setup, Docit stores your provider config in `.docit_ai.yml` with restricted file permissions and adds that file to `.gitignore` when possible.
|
|
80
|
-
|
|
81
42
|
## Configuration
|
|
82
43
|
|
|
83
44
|
Edit `config/initializers/docit.rb`:
|
|
@@ -87,48 +48,40 @@ Docit.configure do |config|
|
|
|
87
48
|
config.title = "My API"
|
|
88
49
|
config.version = "1.0.0"
|
|
89
50
|
config.description = "Backend API documentation"
|
|
51
|
+
config.default_ui = :scalar # :scalar (default) or :swagger
|
|
90
52
|
|
|
91
|
-
#
|
|
92
|
-
config.default_ui = :scalar
|
|
93
|
-
|
|
94
|
-
# Authentication: pick one (or multiple):
|
|
95
|
-
config.auth :bearer # Bearer token (JWT by default)
|
|
96
|
-
config.auth :basic # HTTP Basic
|
|
97
|
-
config.auth :api_key, name: "X-API-Key", # API key in header
|
|
98
|
-
location: "header"
|
|
99
|
-
|
|
100
|
-
# Tag descriptions (shown in the documentation sidebar):
|
|
53
|
+
config.auth :bearer # Bearer token (JWT)
|
|
101
54
|
config.tag "Users", description: "User account management"
|
|
102
|
-
config.tag "Auth", description: "Authentication endpoints"
|
|
103
|
-
|
|
104
|
-
# Server URLs (shown in the server dropdown):
|
|
105
55
|
config.server "https://api.example.com", description: "Production"
|
|
106
|
-
config.server "https://staging.example.com", description: "Staging"
|
|
107
|
-
config.server "http://localhost:3000", description: "Development"
|
|
108
56
|
end
|
|
109
57
|
```
|
|
110
58
|
|
|
111
|
-
|
|
59
|
+
See the [full configuration reference](https://docitruby.dev/docs/configuration) for all options including `license`, `contact`, `terms_of_service`, multiple auth schemes, and server URLs.
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
112
62
|
|
|
113
|
-
Docit supports two styles
|
|
63
|
+
Docit supports two styles. Choose whichever fits your project or mix both.
|
|
114
64
|
|
|
115
65
|
### Style 1: Inline (simple APIs)
|
|
116
66
|
|
|
117
|
-
Add `
|
|
67
|
+
Add `doc_for` blocks directly in your controller:
|
|
118
68
|
|
|
119
69
|
```ruby
|
|
120
70
|
class Api::V1::UsersController < ApplicationController
|
|
121
|
-
|
|
71
|
+
doc_for :index do
|
|
122
72
|
summary "List all users"
|
|
123
73
|
tags "Users"
|
|
124
74
|
response 200, "Users retrieved"
|
|
125
75
|
end
|
|
76
|
+
|
|
126
77
|
def index
|
|
127
78
|
# your code
|
|
128
79
|
end
|
|
129
80
|
end
|
|
130
81
|
```
|
|
131
82
|
|
|
83
|
+
> **Upgrading?** The previous `swagger_doc` method still works as an alias for `doc_for`, so existing code won't break.
|
|
84
|
+
|
|
132
85
|
### Style 2: Separate doc files (recommended for larger APIs)
|
|
133
86
|
|
|
134
87
|
Keep controllers clean by defining docs in dedicated files:
|
|
@@ -140,387 +93,70 @@ module Api::V1::UsersDocs
|
|
|
140
93
|
|
|
141
94
|
doc :index do
|
|
142
95
|
summary "List all users"
|
|
143
|
-
description "Returns a paginated list of users"
|
|
144
96
|
tags "Users"
|
|
145
97
|
|
|
146
|
-
parameter :page, location: :query, type: :integer, description: "Page number"
|
|
147
|
-
|
|
148
98
|
response 200, "Users retrieved" do
|
|
149
99
|
property :users, type: :array, items: :object do
|
|
150
100
|
property :id, type: :integer, example: 1
|
|
151
101
|
property :email, type: :string, example: "user@example.com"
|
|
152
102
|
end
|
|
153
|
-
property :total, type: :integer, example: 42
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
doc :create do
|
|
158
|
-
summary "Create a user"
|
|
159
|
-
tags "Users"
|
|
160
|
-
|
|
161
|
-
request_body required: true do
|
|
162
|
-
property :email, type: :string, required: true
|
|
163
|
-
property :password, type: :string, required: true, format: :password
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
response 201, "User created" do
|
|
167
|
-
property :id, type: :integer
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
response 422, "Validation failed" do
|
|
171
|
-
property :errors, type: :object do
|
|
172
|
-
property :email, type: :array, items: :string
|
|
173
|
-
end
|
|
174
103
|
end
|
|
175
104
|
end
|
|
176
105
|
end
|
|
106
|
+
```
|
|
177
107
|
|
|
178
|
-
|
|
108
|
+
```ruby
|
|
109
|
+
# app/controllers/api/v1/users_controller.rb
|
|
179
110
|
class Api::V1::UsersController < ApplicationController
|
|
180
111
|
use_docs Api::V1::UsersDocs
|
|
181
112
|
|
|
182
113
|
def index
|
|
183
114
|
# pure business logic
|
|
184
115
|
end
|
|
185
|
-
|
|
186
|
-
def create
|
|
187
|
-
# pure business logic
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
You can also mix both styles — use `use_docs` for most actions and add inline `swagger_doc` for one-offs:
|
|
193
|
-
|
|
194
|
-
```ruby
|
|
195
|
-
class Api::V1::UsersController < ApplicationController
|
|
196
|
-
use_docs Api::V1::UsersDocs # loads :index and :create from doc file
|
|
197
|
-
|
|
198
|
-
swagger_doc :destroy do # inline doc for this one action
|
|
199
|
-
summary "Delete user"
|
|
200
|
-
tags "Users"
|
|
201
|
-
response 204, "Deleted"
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def index; end
|
|
205
|
-
def create; end
|
|
206
|
-
def destroy; end
|
|
207
|
-
end
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Endpoint documentation DSL
|
|
211
|
-
|
|
212
|
-
The following examples work in both `swagger_doc` blocks and `doc` blocks.
|
|
213
|
-
|
|
214
|
-
### Request bodies
|
|
215
|
-
|
|
216
|
-
```ruby
|
|
217
|
-
swagger_doc :create do
|
|
218
|
-
summary "Create a user"
|
|
219
|
-
tags "Users"
|
|
220
|
-
|
|
221
|
-
request_body required: true do
|
|
222
|
-
property :email, type: :string, required: true, example: "user@example.com"
|
|
223
|
-
property :password, type: :string, required: true, format: :password
|
|
224
|
-
property :name, type: :string, example: "Jane Doe"
|
|
225
|
-
property :profile, type: :object do
|
|
226
|
-
property :bio, type: :string
|
|
227
|
-
property :avatar_url, type: :string, format: :uri
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
response 201, "User created" do
|
|
232
|
-
property :id, type: :integer, example: 1
|
|
233
|
-
property :email, type: :string, example: "user@example.com"
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
response 422, "Validation failed" do
|
|
237
|
-
property :errors, type: :object do
|
|
238
|
-
property :email, type: :array, items: :string
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
end
|
|
242
|
-
def create
|
|
243
|
-
# your code
|
|
244
|
-
end
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
### Path parameters
|
|
248
|
-
|
|
249
|
-
```ruby
|
|
250
|
-
swagger_doc :show do
|
|
251
|
-
summary "Get a user"
|
|
252
|
-
tags "Users"
|
|
253
|
-
|
|
254
|
-
parameter :id, location: :path, type: :integer, required: true, description: "User ID"
|
|
255
|
-
|
|
256
|
-
response 200, "User found" do
|
|
257
|
-
property :id, type: :integer, example: 1
|
|
258
|
-
property :email, type: :string
|
|
259
|
-
property :name, type: :string
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
response 404, "User not found" do
|
|
263
|
-
property :error, type: :string, example: "Not found"
|
|
264
|
-
end
|
|
265
|
-
end
|
|
266
|
-
def show
|
|
267
|
-
# your code
|
|
268
|
-
end
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Enums
|
|
272
|
-
|
|
273
|
-
```ruby
|
|
274
|
-
swagger_doc :index do
|
|
275
|
-
summary "List orders"
|
|
276
|
-
tags "Orders"
|
|
277
|
-
|
|
278
|
-
parameter :status, location: :query, type: :string,
|
|
279
|
-
enum: %w[pending shipped delivered],
|
|
280
|
-
description: "Filter by status"
|
|
281
|
-
|
|
282
|
-
response 200, "Orders list" do
|
|
283
|
-
property :orders, type: :array do
|
|
284
|
-
property :id, type: :integer
|
|
285
|
-
property :status, type: :string, enum: %w[pending shipped delivered]
|
|
286
|
-
end
|
|
287
|
-
end
|
|
288
|
-
end
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### Security
|
|
292
|
-
|
|
293
|
-
Mark endpoints as requiring authentication:
|
|
294
|
-
|
|
295
|
-
```ruby
|
|
296
|
-
swagger_doc :destroy do
|
|
297
|
-
summary "Delete a user"
|
|
298
|
-
tags "Users"
|
|
299
|
-
security :bearer_auth # references the scheme from your config
|
|
300
|
-
|
|
301
|
-
response 204, "User deleted"
|
|
302
|
-
response 401, "Unauthorized"
|
|
303
|
-
end
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Deprecated endpoints
|
|
307
|
-
|
|
308
|
-
```ruby
|
|
309
|
-
swagger_doc :legacy_search do
|
|
310
|
-
summary "Search (legacy)"
|
|
311
|
-
tags "Search"
|
|
312
|
-
deprecated
|
|
313
|
-
|
|
314
|
-
response 200, "Results"
|
|
315
|
-
end
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
### Nested objects and arrays
|
|
319
|
-
|
|
320
|
-
```ruby
|
|
321
|
-
response 200, "Success" do
|
|
322
|
-
property :user, type: :object do
|
|
323
|
-
property :id, type: :integer
|
|
324
|
-
property :name, type: :string
|
|
325
|
-
property :addresses, type: :array do
|
|
326
|
-
property :street, type: :string
|
|
327
|
-
property :city, type: :string
|
|
328
|
-
property :zip, type: :string
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### Response examples
|
|
335
|
-
|
|
336
|
-
```ruby
|
|
337
|
-
response 200, "User found" do
|
|
338
|
-
property :id, type: :integer
|
|
339
|
-
property :email, type: :string
|
|
340
|
-
|
|
341
|
-
example "admin_user",
|
|
342
|
-
{ id: 1, email: "admin@example.com" },
|
|
343
|
-
description: "An admin user"
|
|
344
|
-
|
|
345
|
-
example "regular_user",
|
|
346
|
-
{ id: 2, email: "user@example.com" },
|
|
347
|
-
description: "A regular user"
|
|
348
116
|
end
|
|
349
117
|
```
|
|
350
118
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
Define reusable schemas once and reference them across multiple endpoints:
|
|
354
|
-
|
|
355
|
-
```ruby
|
|
356
|
-
# In config/initializers/docit.rb or a dedicated file:
|
|
357
|
-
Docit.define_schema :User do
|
|
358
|
-
property :id, type: :integer, example: 1
|
|
359
|
-
property :email, type: :string, example: "user@example.com"
|
|
360
|
-
property :name, type: :string, example: "Jane Doe"
|
|
361
|
-
property :address, type: :object do
|
|
362
|
-
property :street, type: :string
|
|
363
|
-
property :city, type: :string
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
Docit.define_schema :Error do
|
|
368
|
-
property :error, type: :string, example: "Not found"
|
|
369
|
-
property :details, type: :array, items: :string
|
|
370
|
-
end
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
Reference them in any endpoint with `schema ref:`:
|
|
374
|
-
|
|
375
|
-
```ruby
|
|
376
|
-
swagger_doc :show do
|
|
377
|
-
summary "Get user"
|
|
378
|
-
tags "Users"
|
|
379
|
-
|
|
380
|
-
response 200, "User found" do
|
|
381
|
-
schema ref: :User
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
response 404, "Not found" do
|
|
385
|
-
schema ref: :Error
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
|
|
389
|
-
swagger_doc :create do
|
|
390
|
-
summary "Create user"
|
|
391
|
-
tags "Users"
|
|
392
|
-
|
|
393
|
-
request_body required: true do
|
|
394
|
-
schema ref: :User
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
response 201, "Created" do
|
|
398
|
-
schema ref: :User
|
|
399
|
-
end
|
|
400
|
-
end
|
|
401
|
-
```
|
|
119
|
+
See the [full DSL reference](https://docitruby.dev/docs/dsl-reference) for request bodies, path parameters, enums, security, nested objects, file uploads, shared schemas, and more.
|
|
402
120
|
|
|
403
|
-
|
|
121
|
+
## AI Documentation
|
|
404
122
|
|
|
405
|
-
|
|
123
|
+
Docit can generate complete API documentation using AI. Works with OpenAI, Anthropic, or Groq (free tier available).
|
|
406
124
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
```ruby
|
|
410
|
-
swagger_doc :upload_avatar do
|
|
411
|
-
summary "Upload avatar"
|
|
412
|
-
tags "Users"
|
|
413
|
-
|
|
414
|
-
request_body required: true, content_type: "multipart/form-data" do
|
|
415
|
-
property :avatar, type: :file, required: true, description: "Avatar image"
|
|
416
|
-
property :caption, type: :string
|
|
417
|
-
end
|
|
418
|
-
|
|
419
|
-
response 201, "Avatar uploaded" do
|
|
420
|
-
property :url, type: :string, format: :uri
|
|
421
|
-
end
|
|
422
|
-
end
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
`type: :file` maps to `{ type: "string", format: "binary" }` in the OpenAPI spec.
|
|
426
|
-
|
|
427
|
-
## AI Automatic Documentation
|
|
428
|
-
|
|
429
|
-
Docit can generate complete API documentation using AI. This works with OpenAI, Anthropic, or Groq (free tier available).
|
|
430
|
-
|
|
431
|
-
### Quick start (included in install)
|
|
432
|
-
|
|
433
|
-
When you run `rails generate docit:install` and choose option 1 (AI automatic docs), everything is set up automatically — provider configuration, doc generation, controller wiring, and tag injection.
|
|
434
|
-
|
|
435
|
-
Before the first AI request, Docit warns that your controller source code will be sent to the selected provider and asks for confirmation in interactive terminals.
|
|
436
|
-
|
|
437
|
-
### Standalone commands
|
|
438
|
-
|
|
439
|
-
You can also set up AI docs separately:
|
|
125
|
+
When you run `rails generate docit:install` and choose AI automatic docs, everything is set up automatically — provider configuration, doc generation, controller wiring, and tag injection.
|
|
440
126
|
|
|
441
127
|
```bash
|
|
442
|
-
#
|
|
128
|
+
# Or set up AI docs separately:
|
|
443
129
|
rails generate docit:ai_setup
|
|
444
|
-
|
|
445
|
-
# Generate docs for all undocumented endpoints
|
|
446
130
|
rails docit:autodoc
|
|
447
131
|
|
|
448
|
-
#
|
|
449
|
-
rails docit:autodoc[Api::V1::UsersController]
|
|
450
|
-
|
|
451
|
-
# Preview what would be generated without writing files
|
|
132
|
+
# Preview without writing files:
|
|
452
133
|
DRY_RUN=1 rails docit:autodoc
|
|
453
134
|
```
|
|
454
135
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
| Provider | Notes |
|
|
458
|
-
|------------|-------|
|
|
459
|
-
| OpenAI | Requires API key from platform.openai.com |
|
|
460
|
-
| Anthropic | Requires API key from console.anthropic.com |
|
|
461
|
-
| Groq | Free tier at console.groq.com |
|
|
462
|
-
|
|
463
|
-
All providers automatically retry on rate-limit (429) errors with exponential backoff, so free-tier usage works out of the box.
|
|
464
|
-
|
|
465
|
-
AI configuration is stored in `.docit_ai.yml`.
|
|
466
|
-
If your app does not have a `.gitignore`, add `.docit_ai.yml` manually.
|
|
467
|
-
|
|
468
|
-
### What the AI generates
|
|
469
|
-
|
|
470
|
-
For each undocumented endpoint, Docit:
|
|
471
|
-
|
|
472
|
-
1. Reads the controller source code
|
|
473
|
-
2. Inspects the route (HTTP method, path, parameters)
|
|
474
|
-
3. Writes the generated doc block to `app/docs/`
|
|
475
|
-
4. Injects `use_docs` into the controller
|
|
476
|
-
5. Adds tag descriptions to the initializer
|
|
477
|
-
|
|
478
|
-
Do not use AI autodoc on controllers that contain secrets, proprietary business rules, or internal comments you do not want sent to an external provider.
|
|
136
|
+
See the [full AI documentation guide](https://docitruby.dev/docs/ai-documentation) for provider details, safety considerations, and standalone commands.
|
|
479
137
|
|
|
480
138
|
## Documentation UIs
|
|
481
139
|
|
|
482
|
-
Docit ships with two documentation UIs, both reading from the same OpenAPI spec:
|
|
483
|
-
|
|
484
140
|
| Path | UI | Notes |
|
|
485
141
|
|------|------|-------|
|
|
486
142
|
| `/api-docs` | Default (Scalar) | Configurable via `config.default_ui` |
|
|
487
|
-
| `/api-docs/scalar` | Scalar API Reference | Modern UI with
|
|
143
|
+
| `/api-docs/scalar` | Scalar API Reference | Modern UI with API client, dark mode |
|
|
488
144
|
| `/api-docs/swagger` | Swagger UI | Classic OpenAPI explorer |
|
|
489
145
|
| `/api-docs/spec` | Raw JSON | OpenAPI 3.0.3 spec |
|
|
490
146
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
## How it works
|
|
147
|
+
## How It Works
|
|
494
148
|
|
|
495
|
-
1. `
|
|
149
|
+
1. `doc_for` registers an **Operation** for each controller action in a global **Registry**
|
|
496
150
|
2. When someone visits `/api-docs/spec`, Docit's **SchemaGenerator** combines all registered operations with your Rails routes (via **RouteInspector**) to produce an OpenAPI 3.0.3 JSON document
|
|
497
151
|
3. The **Engine** serves the configured documentation UI at `/api-docs`, pointing it at the generated spec
|
|
498
152
|
|
|
499
|
-
The DSL is included in all controllers automatically via a Rails Engine initializer — no manual `include` needed if you're using `ActionController::API` or `ActionController::Base`.
|
|
500
|
-
|
|
501
|
-
## Mounting at a different path
|
|
502
|
-
|
|
503
|
-
In `config/routes.rb`:
|
|
504
|
-
|
|
505
|
-
```ruby
|
|
506
|
-
mount Docit::Engine => "/docs" # now at /docs instead of /api-docs
|
|
507
|
-
```
|
|
508
|
-
|
|
509
|
-
## JSON spec only
|
|
510
|
-
|
|
511
|
-
If you just want the raw OpenAPI JSON (e.g., for code generation):
|
|
512
|
-
|
|
513
|
-
```
|
|
514
|
-
GET /api-docs/spec
|
|
515
|
-
```
|
|
516
|
-
|
|
517
153
|
## Development
|
|
518
154
|
|
|
519
155
|
```bash
|
|
520
156
|
git clone https://github.com/S13G/docit.git
|
|
521
157
|
cd docit
|
|
522
158
|
bundle install
|
|
523
|
-
bundle exec rspec
|
|
159
|
+
bundle exec rspec
|
|
524
160
|
```
|
|
525
161
|
|
|
526
162
|
## Contributing
|
|
@@ -62,11 +62,11 @@ module Docit
|
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
routes_file = Rails.root.join("config", "routes.rb")
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
return unless File.exist?(routes_file) && !File.read(routes_file).include?("Docit::Engine")
|
|
66
|
+
|
|
67
|
+
@output.puts "Warning: Docit engine is not mounted in config/routes.rb"
|
|
68
|
+
@output.puts " Run: rails generate docit:install (or add: mount Docit::Engine => \"/api-docs\")"
|
|
69
|
+
@output.puts ""
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def detect_gaps
|
|
@@ -84,20 +84,20 @@ module Docit
|
|
|
84
84
|
@output.puts "Docit will send controller source code to #{config.provider.capitalize} to generate documentation."
|
|
85
85
|
@output.puts "Review the endpoints first if they contain secrets or proprietary logic."
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
return unless @input.respond_to?(:tty?) && @input.tty?
|
|
88
|
+
|
|
89
|
+
loop do
|
|
90
|
+
@output.print "Continue? (y/n): "
|
|
91
|
+
choice = @input.gets.to_s.strip.downcase
|
|
92
|
+
|
|
93
|
+
case choice
|
|
94
|
+
when "y", "yes"
|
|
95
|
+
@output.puts ""
|
|
96
|
+
return
|
|
97
|
+
when "n", "no"
|
|
98
|
+
raise Docit::Error, "Autodoc cancelled."
|
|
99
|
+
else
|
|
100
|
+
@output.puts "Please enter y or n."
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
end
|
|
@@ -138,6 +138,7 @@ module Docit
|
|
|
138
138
|
invalid_output_retries += 1
|
|
139
139
|
if invalid_output_retries <= MAX_INVALID_OUTPUT_RETRIES
|
|
140
140
|
validation_error = e.message
|
|
141
|
+
@output.puts " invalid output, retrying"
|
|
141
142
|
retry
|
|
142
143
|
end
|
|
143
144
|
|
|
@@ -184,11 +185,11 @@ module Docit
|
|
|
184
185
|
|
|
185
186
|
def inject_tags(generated)
|
|
186
187
|
all_tags = generated.values.flatten.join("\n").scan(/tags\s+["']([^"']+)["']/).flatten
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
return unless all_tags.any?
|
|
189
|
+
|
|
190
|
+
injected = TagInjector.new(tags: all_tags).inject
|
|
191
|
+
injected.each { |tag| @output.puts " Added tag \"#{tag}\" to config/initializers/docit.rb" }
|
|
192
|
+
@results[:tags] = injected
|
|
192
193
|
end
|
|
193
194
|
|
|
194
195
|
def strip_markdown_fences(text)
|
|
@@ -8,7 +8,7 @@ module Docit
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def inject
|
|
11
|
-
return []
|
|
11
|
+
return [] unless initializer_path && File.exist?(initializer_path)
|
|
12
12
|
|
|
13
13
|
content = File.read(initializer_path)
|
|
14
14
|
existing_tags = content.scan(/config\.tag\s+["']([^"']+)["']/).flatten
|
data/lib/docit/configuration.rb
CHANGED
|
@@ -17,6 +17,9 @@ module Docit
|
|
|
17
17
|
@security_schemes = {}
|
|
18
18
|
@tags = []
|
|
19
19
|
@servers = []
|
|
20
|
+
@license = nil
|
|
21
|
+
@contact = nil
|
|
22
|
+
@terms_of_service = nil
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
def default_ui=(value)
|
|
@@ -75,5 +78,35 @@ module Docit
|
|
|
75
78
|
def servers
|
|
76
79
|
@servers.dup
|
|
77
80
|
end
|
|
81
|
+
|
|
82
|
+
def license(name:, url: nil)
|
|
83
|
+
entry = { name: name }
|
|
84
|
+
entry[:url] = url if url
|
|
85
|
+
@license = entry
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def license_info
|
|
89
|
+
@license&.dup
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def contact(name: nil, email: nil, url: nil)
|
|
93
|
+
entry = {}
|
|
94
|
+
entry[:name] = name if name
|
|
95
|
+
entry[:email] = email if email
|
|
96
|
+
entry[:url] = url if url
|
|
97
|
+
@contact = entry
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def contact_info
|
|
101
|
+
@contact&.dup
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def terms_of_service(url)
|
|
105
|
+
@terms_of_service = url
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def terms_of_service_url
|
|
109
|
+
@terms_of_service
|
|
110
|
+
end
|
|
78
111
|
end
|
|
79
112
|
end
|
data/lib/docit/doc_file.rb
CHANGED
data/lib/docit/dsl.rb
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Docit
|
|
4
4
|
# Included in all Rails controllers via the Engine.
|
|
5
|
-
# Provides +
|
|
5
|
+
# Provides +doc_for+ and +use_docs+ class methods.
|
|
6
6
|
module DSL
|
|
7
7
|
def self.included(base)
|
|
8
8
|
base.extend(ClassMethods)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
module ClassMethods
|
|
12
|
-
def
|
|
12
|
+
def doc_for(action, &block)
|
|
13
13
|
operation = Operation.new(
|
|
14
14
|
controller: name,
|
|
15
15
|
action: action
|
|
@@ -18,9 +18,12 @@ module Docit
|
|
|
18
18
|
Registry.register(operation)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
# Backward-compatible alias
|
|
22
|
+
alias swagger_doc doc_for
|
|
23
|
+
|
|
21
24
|
def use_docs(doc_module)
|
|
22
25
|
doc_module.actions.each do |action|
|
|
23
|
-
|
|
26
|
+
doc_for(action, &doc_module[action])
|
|
24
27
|
end
|
|
25
28
|
end
|
|
26
29
|
end
|
data/lib/docit/operation.rb
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module Docit
|
|
4
4
|
# Represents the documentation for a single controller action.
|
|
5
|
-
# Created by +
|
|
5
|
+
# Created by +doc_for+ and stored in the {Registry}.
|
|
6
6
|
class Operation
|
|
7
7
|
attr_reader :controller, :action, :_summary, :_description,
|
|
8
8
|
:_tags, :_responses, :_request_body, :_parameters,
|
|
9
|
-
:_security, :_deprecated
|
|
9
|
+
:_security, :_deprecated, :_operation_id
|
|
10
10
|
|
|
11
11
|
def initialize(controller:, action:)
|
|
12
12
|
@controller = controller
|
|
@@ -17,6 +17,7 @@ module Docit
|
|
|
17
17
|
@_request_body = nil
|
|
18
18
|
@_security = []
|
|
19
19
|
@_deprecated = false
|
|
20
|
+
@_operation_id = nil
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def summary(text)
|
|
@@ -35,6 +36,10 @@ module Docit
|
|
|
35
36
|
@_deprecated = value
|
|
36
37
|
end
|
|
37
38
|
|
|
39
|
+
def operation_id(text)
|
|
40
|
+
@_operation_id = text
|
|
41
|
+
end
|
|
42
|
+
|
|
38
43
|
def security(scheme)
|
|
39
44
|
@_security << scheme
|
|
40
45
|
end
|
|
@@ -5,7 +5,7 @@ module Docit
|
|
|
5
5
|
class RouteInspector
|
|
6
6
|
VALID_METHODS = %w[get post put patch delete].freeze
|
|
7
7
|
|
|
8
|
-
# Eagerly loads controller classes so
|
|
8
|
+
# Eagerly loads controller classes so doc_for/use_docs macros run before spec generation.
|
|
9
9
|
def self.eager_load_controllers!
|
|
10
10
|
return if defined?(Rails).nil? || Rails.application.routes.nil?
|
|
11
11
|
|
|
@@ -12,11 +12,7 @@ module Docit
|
|
|
12
12
|
|
|
13
13
|
spec = {
|
|
14
14
|
openapi: "3.0.3",
|
|
15
|
-
info:
|
|
16
|
-
title: config.title,
|
|
17
|
-
version: config.version,
|
|
18
|
-
description: config.description
|
|
19
|
-
},
|
|
15
|
+
info: build_info(config),
|
|
20
16
|
paths: build_paths,
|
|
21
17
|
components: {
|
|
22
18
|
securitySchemes: config.security_schemes
|
|
@@ -37,6 +33,18 @@ module Docit
|
|
|
37
33
|
|
|
38
34
|
private
|
|
39
35
|
|
|
36
|
+
def build_info(config)
|
|
37
|
+
info = {
|
|
38
|
+
title: config.title,
|
|
39
|
+
version: config.version,
|
|
40
|
+
description: config.description
|
|
41
|
+
}
|
|
42
|
+
info[:license] = config.license_info if config.license_info
|
|
43
|
+
info[:contact] = config.contact_info if config.contact_info
|
|
44
|
+
info[:termsOfService] = config.terms_of_service_url if config.terms_of_service_url
|
|
45
|
+
info
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
def build_paths
|
|
41
49
|
paths = {}
|
|
42
50
|
|
|
@@ -58,6 +66,7 @@ module Docit
|
|
|
58
66
|
|
|
59
67
|
def build_operation(operation)
|
|
60
68
|
result = {
|
|
69
|
+
operationId: operation._operation_id || generate_operation_id(operation),
|
|
61
70
|
summary: operation._summary || operation.action.humanize,
|
|
62
71
|
description: operation._description || "",
|
|
63
72
|
tags: operation._tags,
|
|
@@ -183,5 +192,15 @@ module Docit
|
|
|
183
192
|
hash[ex[:name].to_s] = entry
|
|
184
193
|
end
|
|
185
194
|
end
|
|
195
|
+
|
|
196
|
+
def generate_operation_id(operation)
|
|
197
|
+
# "Api::V1::UsersController" → "users" ; "index" → "listUsers"
|
|
198
|
+
resource = operation.controller
|
|
199
|
+
.gsub(/.*::/, "") # strip namespace
|
|
200
|
+
.gsub(/Controller$/, "") # strip suffix
|
|
201
|
+
action = operation.action
|
|
202
|
+
|
|
203
|
+
"#{action}_#{resource}".gsub("::", "_").downcase
|
|
204
|
+
end
|
|
186
205
|
end
|
|
187
206
|
end
|
data/lib/docit/version.rb
CHANGED
|
@@ -102,7 +102,7 @@ module Docit
|
|
|
102
102
|
say ""
|
|
103
103
|
say "Next steps:"
|
|
104
104
|
say " 1. Edit config/initializers/docit.rb to customize your API docs"
|
|
105
|
-
say " 2. Add
|
|
105
|
+
say " 2. Add doc_for blocks or create doc files under app/docs/"
|
|
106
106
|
say " 3. Visit /api-docs to see your Swagger UI"
|
|
107
107
|
say ""
|
|
108
108
|
say "You can set up docs later with:"
|
|
@@ -146,7 +146,7 @@ module Docit
|
|
|
146
146
|
|
|
147
147
|
def update_gitignore
|
|
148
148
|
gitignore = Rails.root.join(".gitignore")
|
|
149
|
-
|
|
149
|
+
unless File.exist?(gitignore)
|
|
150
150
|
say "Warning: .gitignore not found. Add .docit_ai.yml manually to avoid committing your API key.", :yellow
|
|
151
151
|
return
|
|
152
152
|
end
|
|
@@ -167,7 +167,7 @@ module Docit
|
|
|
167
167
|
choice = ask(prompt).to_s.strip
|
|
168
168
|
return choice if choices.include?(choice)
|
|
169
169
|
|
|
170
|
-
say "Invalid choice. Please enter #{choices.join(
|
|
170
|
+
say "Invalid choice. Please enter #{choices.join(", ")}.", :red
|
|
171
171
|
end
|
|
172
172
|
end
|
|
173
173
|
|
data/lib/tasks/docit.rake
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
namespace :docit do
|
|
4
4
|
desc "Generate documentation for undocumented API endpoints using AI"
|
|
5
5
|
task :autodoc, [:controller] => :environment do |_t, args|
|
|
6
|
-
dry_run = ENV.fetch("DRY_RUN", "0") == "1"
|
|
6
|
+
dry_run = ENV.fetch("DRY_RUN", "0") == "1"
|
|
7
7
|
controller_filter = args[:controller]
|
|
8
8
|
|
|
9
9
|
runner = Docit::Ai::AutodocRunner.new(
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- S13G
|
|
@@ -43,8 +43,6 @@ files:
|
|
|
43
43
|
- Rakefile
|
|
44
44
|
- app/controllers/docit/ui_controller.rb
|
|
45
45
|
- config/routes.rb
|
|
46
|
-
- docs/images/scalar_image.png
|
|
47
|
-
- docs/images/swagger_image.png
|
|
48
46
|
- lib/docit.rb
|
|
49
47
|
- lib/docit/ai.rb
|
|
50
48
|
- lib/docit/ai/anthropic_client.rb
|
|
@@ -80,14 +78,14 @@ files:
|
|
|
80
78
|
- lib/generators/docit/install/templates/initializer.rb
|
|
81
79
|
- lib/tasks/docit.rake
|
|
82
80
|
- sig/docit.rbs
|
|
83
|
-
homepage: https://
|
|
81
|
+
homepage: https://docitruby.dev
|
|
84
82
|
licenses:
|
|
85
83
|
- MIT
|
|
86
84
|
metadata:
|
|
87
|
-
homepage_uri: https://
|
|
85
|
+
homepage_uri: https://docitruby.dev
|
|
88
86
|
source_code_uri: https://github.com/S13G/docit
|
|
89
87
|
changelog_uri: https://github.com/S13G/docit/blob/master/CHANGELOG.md
|
|
90
|
-
documentation_uri: https://
|
|
88
|
+
documentation_uri: https://docitruby.dev/docs
|
|
91
89
|
bug_tracker_uri: https://github.com/S13G/docit/issues
|
|
92
90
|
rubygems_mfa_required: 'true'
|
|
93
91
|
rdoc_options: []
|
|
Binary file
|
|
Binary file
|