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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ac8acf7fd2b736bb2c89c63a63bca482239783457d7572d864e0257a3a2c6cd
4
- data.tar.gz: 1605b07b832dc73f4e7f00e0840aa72267cbb60262e17baba6842134ee576e19
3
+ metadata.gz: 39589c6800b65d7a0ad55701378b345f18277735df3511cce965bc889035e74f
4
+ data.tar.gz: 91c392bded5bbd0897222859feab4d68e8c0d3064d4054e6b75509a325ced2d0
5
5
  SHA512:
6
- metadata.gz: a72fa34e950fdf918daab680c287311401a4059fa3b8d0bf16a0ebcef210ed607b697d3ad58a3343bf7d105a2a11d717efd0f8ee239464a82f58ca5f934b1e79
7
- data.tar.gz: 96516820d968faae672a4caa7b6c52c9d79356b6366d09edaa019badb2c6949c0b4087115e6f306f559904b5dbcb02b594c2e0e58e864458c0c460e381d4d894
6
+ metadata.gz: 1ea253c903e6a90eb3754ed9f4a586adcc7339c831d9623401cc4bb53256359c81e069bba4067a12379da350fbf354b50bfd14420ae0aa75c3841c74942ae5f2
7
+ data.tar.gz: 8441b41ae22a25f1bd29514fbdcb425b4bbd56b591da6904df0c9ad070a7ac830b1eb9338783a8c751d8f648db4826d69b7755a0f42cd320baaf8e3ebeb7c628
@@ -11,7 +11,7 @@ A clear and concise description of the bug.
11
11
  ## Steps to Reproduce
12
12
 
13
13
  1. Configure Docit with `...`
14
- 2. Add `swagger_doc` to `...`
14
+ 2. Add `doc_for` to `...`
15
15
  3. Visit `/api-docs`
16
16
  4. See error
17
17
 
@@ -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
- swagger_doc :index do
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: `swagger_doc` macro for inline controller documentation
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 # swagger_doc macro
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
  ![Swagger UI](docs/images/swagger_image.png)
13
13
 
14
- ## Table Of Contents
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
- # Documentation UI: :scalar (default) or :swagger
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
- ## Usage
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 for documenting endpoints. Choose whichever fits your project or mix both.
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 `swagger_doc` blocks directly in your controller:
67
+ Add `doc_for` blocks directly in your controller:
118
68
 
119
69
  ```ruby
120
70
  class Api::V1::UsersController < ApplicationController
121
- swagger_doc :index do
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
- # app/controllers/api/v1/users_controller.rb — stays clean!
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
- ### Shared schemas (`$ref`)
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
- This outputs `$ref: '#/components/schemas/User'` in the spec — Swagger UI resolves it automatically.
121
+ ## AI Documentation
404
122
 
405
- ### File uploads
123
+ Docit can generate complete API documentation using AI. Works with OpenAI, Anthropic, or Groq (free tier available).
406
124
 
407
- Use `type: :file` with `content_type: "multipart/form-data"` for file upload endpoints:
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
- # Configure your AI provider (one-time setup)
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
- # Generate docs for a specific controller
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
- ### Supported providers
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 built-in API client, dark mode, code samples |
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
- Both UIs include a navigation bar to switch between them. Set `config.default_ui = :swagger` to make Swagger the default at `/api-docs`.
492
-
493
- ## How it works
147
+ ## How It Works
494
148
 
495
- 1. `swagger_doc` registers an **Operation** for each controller action in a global **Registry**
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 # run all tests
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
- if File.exist?(routes_file) && !File.read(routes_file).include?("Docit::Engine")
66
- @output.puts "Warning: Docit engine is not mounted in config/routes.rb"
67
- @output.puts " Run: rails generate docit:install (or add: mount Docit::Engine => \"/api-docs\")"
68
- @output.puts ""
69
- end
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
- if @input.respond_to?(:tty?) && @input.tty?
88
- loop do
89
- @output.print "Continue? (y/n): "
90
- choice = @input.gets.to_s.strip.downcase
91
-
92
- case choice
93
- when "y", "yes"
94
- @output.puts ""
95
- return
96
- when "n", "no"
97
- raise Docit::Error, "Autodoc cancelled."
98
- else
99
- @output.puts "Please enter y or n."
100
- end
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
- if all_tags.any?
188
- injected = TagInjector.new(tags: all_tags).inject
189
- injected.each { |tag| @output.puts " Added tag \"#{tag}\" to config/initializers/docit.rb" }
190
- @results[:tags] = injected
191
- end
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 [] if initializer_path && File.exist?(initializer_path) == false
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
@@ -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
@@ -40,7 +40,7 @@ module Docit
40
40
  base.instance_variable_set(:@_docs, {})
41
41
  end
42
42
 
43
- # The block receives the same DSL as swagger_doc.
43
+ # The block receives the same DSL as doc_for.
44
44
  def doc(action, &block)
45
45
  @_docs[action.to_sym] = block
46
46
  end
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 +swagger_doc+ and +use_docs+ class methods.
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 swagger_doc(action, &block)
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
- swagger_doc(action, &doc_module[action])
26
+ doc_for(action, &doc_module[action])
24
27
  end
25
28
  end
26
29
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  module Docit
4
4
  # Represents the documentation for a single controller action.
5
- # Created by +swagger_doc+ and stored in the {Registry}.
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 swagger_doc/use_docs macros run before spec generation.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docit
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -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 swagger_doc blocks or create doc files under app/docs/"
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
- if !(File.exist?(gitignore))
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(', ')}.", :red
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" || ARGV.include?("--dry-run")
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.3.1
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://github.com/S13G/docit
81
+ homepage: https://docitruby.dev
84
82
  licenses:
85
83
  - MIT
86
84
  metadata:
87
- homepage_uri: https://github.com/S13G/docit
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://rubydoc.info/gems/docit
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