docit 0.1.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 +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +31 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- data/.github/workflows/ci.yml +30 -0
- data/CHANGELOG.md +15 -0
- data/CODE_OF_CONDUCT.md +39 -0
- data/CONTRIBUTING.md +78 -0
- data/LICENSE.txt +21 -0
- data/README.md +416 -0
- data/Rakefile +12 -0
- data/app/controllers/docit/ui_controller.rb +56 -0
- data/config/routes.rb +6 -0
- data/lib/docit/builders/parameter_builder.rb +28 -0
- data/lib/docit/builders/request_body_builder.rb +45 -0
- data/lib/docit/builders/response_builder.rb +47 -0
- data/lib/docit/configuration.rb +66 -0
- data/lib/docit/doc_file.rb +56 -0
- data/lib/docit/dsl.rb +28 -0
- data/lib/docit/engine.rb +19 -0
- data/lib/docit/operation.rb +58 -0
- data/lib/docit/registry.rb +26 -0
- data/lib/docit/route_inspector.rb +60 -0
- data/lib/docit/schema_definition.rb +33 -0
- data/lib/docit/schema_generator.rb +187 -0
- data/lib/docit/version.rb +5 -0
- data/lib/docit.rb +48 -0
- data/lib/generators/docit/install/install_generator.rb +29 -0
- data/lib/generators/docit/install/templates/initializer.rb +18 -0
- data/sig/docit.rbs +4 -0
- metadata +90 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docit
|
|
4
|
+
# Converts the Registry of operations and Configuration into an OpenAPI 3.0.3 spec hash.
|
|
5
|
+
class SchemaGenerator
|
|
6
|
+
def self.generate
|
|
7
|
+
new.generate
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def generate
|
|
11
|
+
config = Docit.configuration
|
|
12
|
+
|
|
13
|
+
spec = {
|
|
14
|
+
openapi: "3.0.3",
|
|
15
|
+
info: {
|
|
16
|
+
title: config.title,
|
|
17
|
+
version: config.version,
|
|
18
|
+
description: config.description
|
|
19
|
+
},
|
|
20
|
+
paths: build_paths,
|
|
21
|
+
components: {
|
|
22
|
+
securitySchemes: config.security_schemes
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
tag_defs = config.tags
|
|
27
|
+
spec[:tags] = tag_defs if tag_defs.any?
|
|
28
|
+
|
|
29
|
+
server_defs = config.servers
|
|
30
|
+
spec[:servers] = server_defs if server_defs.any?
|
|
31
|
+
|
|
32
|
+
schemas = build_component_schemas
|
|
33
|
+
spec[:components][:schemas] = schemas if schemas.any?
|
|
34
|
+
|
|
35
|
+
spec
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def build_paths
|
|
41
|
+
paths = {}
|
|
42
|
+
|
|
43
|
+
Docit::Registry.operations.each do |operation|
|
|
44
|
+
routes = RouteInspector.routes_for(operation.controller, operation.action)
|
|
45
|
+
next if routes.empty?
|
|
46
|
+
|
|
47
|
+
routes.each do |route|
|
|
48
|
+
path = route[:path]
|
|
49
|
+
method = route[:method]
|
|
50
|
+
|
|
51
|
+
paths[path] ||= {}
|
|
52
|
+
paths[path][method] = build_operation(operation)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
paths
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_operation(operation)
|
|
60
|
+
result = {
|
|
61
|
+
summary: operation._summary || operation.action.humanize,
|
|
62
|
+
description: operation._description || "",
|
|
63
|
+
tags: operation._tags,
|
|
64
|
+
responses: build_responses(operation._responses)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
params = operation._parameters.params
|
|
68
|
+
result[:parameters] = params if params.any?
|
|
69
|
+
|
|
70
|
+
result[:requestBody] = build_request_body(operation._request_body) if operation._request_body
|
|
71
|
+
result[:deprecated] = true if operation._deprecated
|
|
72
|
+
result[:security] = operation._security.map { |s| { s.to_s => [] } } if operation._security.any?
|
|
73
|
+
|
|
74
|
+
result
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def build_responses(response_builders)
|
|
78
|
+
return { "200" => { description: "Success" } } if response_builders.empty?
|
|
79
|
+
|
|
80
|
+
response_builders.each_with_object({}) do |builder, hash|
|
|
81
|
+
entry = { description: builder.description }
|
|
82
|
+
|
|
83
|
+
if builder.schema_ref
|
|
84
|
+
schema = { "$ref" => "#/components/schemas/#{builder.schema_ref}" }
|
|
85
|
+
content = { "application/json" => { schema: schema } }
|
|
86
|
+
content["application/json"][:examples] = build_examples(builder.examples) if builder.examples.any?
|
|
87
|
+
entry[:content] = content
|
|
88
|
+
elsif builder.properties.any?
|
|
89
|
+
schema = {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: build_properties(builder.properties)
|
|
92
|
+
}
|
|
93
|
+
content = { "application/json" => { schema: schema } }
|
|
94
|
+
content["application/json"][:examples] = build_examples(builder.examples) if builder.examples.any?
|
|
95
|
+
entry[:content] = content
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
hash[builder.status.to_s] = entry
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def build_request_body(request_body_builder)
|
|
103
|
+
if request_body_builder.schema_ref
|
|
104
|
+
schema = { "$ref" => "#/components/schemas/#{request_body_builder.schema_ref}" }
|
|
105
|
+
else
|
|
106
|
+
schema = {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: build_properties(request_body_builder.properties)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
required_properties = request_body_builder.required_properties
|
|
112
|
+
schema[:required] = required_properties if required_properties.any?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
{
|
|
116
|
+
required: request_body_builder.required,
|
|
117
|
+
content: {
|
|
118
|
+
request_body_builder.content_type => { schema: schema }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def build_properties(props)
|
|
124
|
+
props.each_with_object({}) do |prop, hash|
|
|
125
|
+
schema = build_property_schema(prop)
|
|
126
|
+
hash[prop[:name].to_s] = schema
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def build_property_schema(prop)
|
|
131
|
+
type = prop[:type].to_s
|
|
132
|
+
|
|
133
|
+
if type == "file"
|
|
134
|
+
schema = { type: "string", format: "binary" }
|
|
135
|
+
schema[:description] = prop[:description] if prop[:description]
|
|
136
|
+
schema
|
|
137
|
+
elsif type == "array"
|
|
138
|
+
schema = { type: "array" }
|
|
139
|
+
if prop[:children]
|
|
140
|
+
schema[:items] = {
|
|
141
|
+
type: "object",
|
|
142
|
+
properties: build_properties(prop[:children])
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
items_type = prop[:items]&.to_s || "string"
|
|
146
|
+
schema[:items] = { type: items_type }
|
|
147
|
+
end
|
|
148
|
+
schema[:description] = prop[:description] if prop[:description]
|
|
149
|
+
schema[:example] = prop[:example] if prop[:example]
|
|
150
|
+
schema
|
|
151
|
+
elsif type == "object" && prop[:children]
|
|
152
|
+
schema = {
|
|
153
|
+
type: "object",
|
|
154
|
+
properties: build_properties(prop[:children])
|
|
155
|
+
}
|
|
156
|
+
schema[:description] = prop[:description] if prop[:description]
|
|
157
|
+
schema[:example] = prop[:example] if prop[:example]
|
|
158
|
+
schema
|
|
159
|
+
else
|
|
160
|
+
schema = { type: type }
|
|
161
|
+
schema[:format] = prop[:format].to_s if prop[:format]
|
|
162
|
+
schema[:enum] = prop[:enum] if prop[:enum]
|
|
163
|
+
schema[:example] = prop[:example] if prop[:example]
|
|
164
|
+
schema[:description] = prop[:description] if prop[:description]
|
|
165
|
+
schema
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def build_component_schemas
|
|
170
|
+
Docit.schemas.each_with_object({}) do |(name, definition), hash|
|
|
171
|
+
schema = {
|
|
172
|
+
type: "object",
|
|
173
|
+
properties: build_properties(definition.properties)
|
|
174
|
+
}
|
|
175
|
+
hash[name.to_s] = schema
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def build_examples(examples)
|
|
180
|
+
examples.each_with_object({}) do |ex, hash|
|
|
181
|
+
entry = { value: ex[:value] }
|
|
182
|
+
entry[:description] = ex[:description] if ex[:description]
|
|
183
|
+
hash[ex[:name].to_s] = entry
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
data/lib/docit.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "docit/version"
|
|
4
|
+
require_relative "docit/configuration"
|
|
5
|
+
require_relative "docit/registry"
|
|
6
|
+
require_relative "docit/builders/request_body_builder"
|
|
7
|
+
require_relative "docit/builders/response_builder"
|
|
8
|
+
require_relative "docit/builders/parameter_builder"
|
|
9
|
+
require_relative "docit/operation"
|
|
10
|
+
require_relative "docit/schema_definition"
|
|
11
|
+
require_relative "docit/doc_file"
|
|
12
|
+
require_relative "docit/route_inspector"
|
|
13
|
+
require_relative "docit/schema_generator"
|
|
14
|
+
require_relative "docit/dsl"
|
|
15
|
+
|
|
16
|
+
# Docit is a decorator-style API documentation gem for Ruby on Rails.
|
|
17
|
+
# It generates OpenAPI 3.0.3 specs from clean DSL macros on your controllers.
|
|
18
|
+
module Docit
|
|
19
|
+
class Error < StandardError; end
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def configure
|
|
23
|
+
yield configuration
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def configuration
|
|
27
|
+
@configuration ||= Configuration.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reset_configuration!
|
|
31
|
+
@configuration = Configuration.new
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def schemas
|
|
35
|
+
@schemas ||= {}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def define_schema(name, &block)
|
|
39
|
+
definition = SchemaDefinition.new(name)
|
|
40
|
+
definition.instance_eval(&block) if block_given?
|
|
41
|
+
schemas[name.to_sym] = definition
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset_schemas!
|
|
45
|
+
@schemas = {}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docit
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
desc "Creates a Docit initializer and mounts the engine in routes"
|
|
7
|
+
source_root File.expand_path("templates", __dir__)
|
|
8
|
+
|
|
9
|
+
def copy_initializer
|
|
10
|
+
template "initializer.rb", "config/initializers/docit.rb"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def mount_engine
|
|
14
|
+
route 'mount Docit::Engine => "/api-docs"'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def print_instructions
|
|
18
|
+
say ""
|
|
19
|
+
say "Docit installed successfully!", :green
|
|
20
|
+
say ""
|
|
21
|
+
say "Next steps:"
|
|
22
|
+
say " 1. Edit config/initializers/docit.rb to customize your API docs"
|
|
23
|
+
say " 2. Add swagger_doc blocks to your controller actions"
|
|
24
|
+
say " 3. Visit /api-docs to see your Swagger UI"
|
|
25
|
+
say ""
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Docit.configure do |config|
|
|
4
|
+
# The title shown in Swagger UI
|
|
5
|
+
config.title = "<%= Rails.application.class.module_parent_name rescue 'My API' %>"
|
|
6
|
+
|
|
7
|
+
# API version
|
|
8
|
+
config.version = "1.0.0"
|
|
9
|
+
|
|
10
|
+
# Description shown in Swagger UI
|
|
11
|
+
config.description = "API documentation powered by Docit"
|
|
12
|
+
|
|
13
|
+
# Authentication scheme (options: :bearer, :basic, :api_key)
|
|
14
|
+
# config.auth :bearer
|
|
15
|
+
|
|
16
|
+
# For API key auth:
|
|
17
|
+
# config.auth :api_key, name: "X-API-Key", location: "header"
|
|
18
|
+
end
|
data/sig/docit.rbs
ADDED
metadata
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: docit
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- S13G
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
description: Docit lets you write OpenAPI 3.0 docs as clean DSL macros directly on
|
|
27
|
+
your Rails controller actions. No RSpec integration required, no external doc files.
|
|
28
|
+
Just annotate and go.
|
|
29
|
+
email:
|
|
30
|
+
- siegdomain1@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
|
36
|
+
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
|
37
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
|
38
|
+
- ".github/workflows/ci.yml"
|
|
39
|
+
- CHANGELOG.md
|
|
40
|
+
- CODE_OF_CONDUCT.md
|
|
41
|
+
- CONTRIBUTING.md
|
|
42
|
+
- LICENSE.txt
|
|
43
|
+
- README.md
|
|
44
|
+
- Rakefile
|
|
45
|
+
- app/controllers/docit/ui_controller.rb
|
|
46
|
+
- config/routes.rb
|
|
47
|
+
- lib/docit.rb
|
|
48
|
+
- lib/docit/builders/parameter_builder.rb
|
|
49
|
+
- lib/docit/builders/request_body_builder.rb
|
|
50
|
+
- lib/docit/builders/response_builder.rb
|
|
51
|
+
- lib/docit/configuration.rb
|
|
52
|
+
- lib/docit/doc_file.rb
|
|
53
|
+
- lib/docit/dsl.rb
|
|
54
|
+
- lib/docit/engine.rb
|
|
55
|
+
- lib/docit/operation.rb
|
|
56
|
+
- lib/docit/registry.rb
|
|
57
|
+
- lib/docit/route_inspector.rb
|
|
58
|
+
- lib/docit/schema_definition.rb
|
|
59
|
+
- lib/docit/schema_generator.rb
|
|
60
|
+
- lib/docit/version.rb
|
|
61
|
+
- lib/generators/docit/install/install_generator.rb
|
|
62
|
+
- lib/generators/docit/install/templates/initializer.rb
|
|
63
|
+
- sig/docit.rbs
|
|
64
|
+
homepage: https://github.com/S13G/docket
|
|
65
|
+
licenses:
|
|
66
|
+
- MIT
|
|
67
|
+
metadata:
|
|
68
|
+
homepage_uri: https://github.com/S13G/docket
|
|
69
|
+
source_code_uri: https://github.com/S13G/docket
|
|
70
|
+
changelog_uri: https://github.com/S13G/docket/blob/main/CHANGELOG.md
|
|
71
|
+
documentation_uri: https://rubydoc.info/gems/docit
|
|
72
|
+
rubygems_mfa_required: 'true'
|
|
73
|
+
rdoc_options: []
|
|
74
|
+
require_paths:
|
|
75
|
+
- lib
|
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: 3.2.0
|
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
82
|
+
requirements:
|
|
83
|
+
- - ">="
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '0'
|
|
86
|
+
requirements: []
|
|
87
|
+
rubygems_version: 4.0.3
|
|
88
|
+
specification_version: 4
|
|
89
|
+
summary: Decorator-style Swagger/OpenAPI documentation generator for Ruby on Rails.
|
|
90
|
+
test_files: []
|