dox 2.4.0 → 3.0.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/workflows/ci.yml +34 -0
- data/.rubocop.yml +76 -9
- data/.ruby-version +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +14 -1
- data/README.md +27 -20
- data/Rakefile +7 -1
- data/dox.gemspec +8 -15
- data/lib/dox/config.rb +8 -0
- data/lib/dox/dsl/resource.rb +2 -0
- data/lib/dox/entities/action.rb +8 -3
- data/lib/dox/entities/example.rb +10 -5
- data/lib/dox/entities/resource.rb +3 -1
- data/lib/dox/entities/resource_group.rb +2 -1
- data/lib/dox/formatters/base.rb +2 -1
- data/lib/dox/html_renderer.rb +71 -0
- data/lib/dox/printers/action_printer.rb +2 -1
- data/lib/dox/printers/base_printer.rb +6 -2
- data/lib/dox/printers/document_printer.rb +3 -7
- data/lib/dox/printers/example_response_printer.rb +1 -1
- data/lib/dox/printers/resource_group_printer.rb +1 -1
- data/lib/dox/printers/resource_printer.rb +1 -1
- data/lib/dox/redocly_adapter.rb +32 -0
- data/lib/dox/version.rb +1 -1
- data/lib/dox.rb +7 -1
- metadata +18 -124
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a254b169809b99600afcc0dae0e46f55f6214604ceab941215dee84c48d17af
|
|
4
|
+
data.tar.gz: a3172985b3aeeff16496a2b192808c90429519ac79c4ddb2b2a4b36f7cbc21f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e47d00386e96ffb5801fcacbafa0f4885dfb7574cbf458e253f0e88d1a6018de7a4efaff29399653c07b625d26695be4b9110ec87284f1be8224374405f21bd9
|
|
7
|
+
data.tar.gz: d0063b18dfe5c953bacd5b226872f4f19e8b2524c90740741d94c33f17557c48285e540695acff22d3a8b118ce845c11f0659b6b38882671c6f73b77710b48eb
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [master]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
rubocop:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- name: Set up Ruby
|
|
14
|
+
uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
ruby-version: '3.1'
|
|
17
|
+
bundler-cache: true
|
|
18
|
+
- name: Run rubocop
|
|
19
|
+
run: bundle exec rubocop
|
|
20
|
+
test:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
ruby-version: ['3.1', '3.2', '3.3', '3.4', '4.0']
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
|
29
|
+
uses: ruby/setup-ruby@v1
|
|
30
|
+
with:
|
|
31
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
32
|
+
bundler-cache: true
|
|
33
|
+
- name: Run tests
|
|
34
|
+
run: bundle exec rspec
|
data/.rubocop.yml
CHANGED
|
@@ -1,17 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
inherit_gem:
|
|
2
|
+
rubocop-infinum: rubocop.yml
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
plugins:
|
|
5
|
+
- rubocop-infinum
|
|
6
|
+
- rubocop-rake
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
AllCops:
|
|
9
|
+
TargetRubyVersion: 3.1
|
|
10
|
+
|
|
11
|
+
Rails:
|
|
12
|
+
Enabled: false
|
|
13
|
+
|
|
14
|
+
Naming/BlockForwarding:
|
|
15
|
+
Enabled: false
|
|
16
|
+
|
|
17
|
+
Style/ArgumentsForwarding:
|
|
18
|
+
Enabled: false
|
|
9
19
|
|
|
10
20
|
Style/FrozenStringLiteralComment:
|
|
11
21
|
Enabled: false
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
|
|
23
|
+
Style/HashAsLastArrayItem:
|
|
24
|
+
Enabled: false
|
|
25
|
+
|
|
26
|
+
Style/MissingRespondToMissing:
|
|
27
|
+
Enabled: false
|
|
28
|
+
|
|
29
|
+
Style/HashTransformValues:
|
|
30
|
+
Enabled: false
|
|
31
|
+
|
|
32
|
+
Style/OneClassPerFile:
|
|
33
|
+
Enabled: false
|
|
34
|
+
|
|
35
|
+
Lint/ConstantDefinitionInBlock:
|
|
36
|
+
Enabled: false
|
|
37
|
+
|
|
38
|
+
Performance/RegexpMatch:
|
|
39
|
+
Enabled: false
|
|
40
|
+
|
|
41
|
+
RSpec/MultipleExpectations:
|
|
42
|
+
Max: 5
|
|
43
|
+
|
|
44
|
+
RSpec/NestedGroups:
|
|
45
|
+
Max: 5
|
|
46
|
+
|
|
47
|
+
RSpec/MultipleMemoizedHelpers:
|
|
48
|
+
Enabled: false
|
|
49
|
+
|
|
50
|
+
RSpec/IndexedLet:
|
|
51
|
+
Enabled: false
|
|
52
|
+
|
|
53
|
+
RSpec/ExpectInHook:
|
|
54
|
+
Enabled: false
|
|
55
|
+
|
|
56
|
+
RSpec/BeEq:
|
|
57
|
+
Enabled: false
|
|
58
|
+
|
|
59
|
+
RSpec/AnyInstance:
|
|
60
|
+
Enabled: false
|
|
61
|
+
|
|
62
|
+
RSpec/VerifiedDoubles:
|
|
63
|
+
Enabled: false
|
|
64
|
+
|
|
65
|
+
RSpec/SpecFilePathFormat:
|
|
66
|
+
Enabled: false
|
|
67
|
+
|
|
68
|
+
RSpec/VoidExpect:
|
|
69
|
+
Enabled: false
|
|
70
|
+
|
|
71
|
+
RSpec/NoExpectationExample:
|
|
72
|
+
Enabled: false
|
|
73
|
+
|
|
74
|
+
RSpec/ReceiveMessages:
|
|
75
|
+
Enabled: false
|
|
76
|
+
|
|
77
|
+
RSpec/NamedSubject:
|
|
78
|
+
Enabled: false
|
|
79
|
+
|
|
80
|
+
RSpec/ContextWording:
|
|
81
|
+
Enabled: false
|
|
15
82
|
|
|
16
|
-
|
|
83
|
+
RSpec/LeakyConstantDeclaration:
|
|
17
84
|
Enabled: false
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.1.7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.0
|
|
4
|
+
|
|
5
|
+
### Enhancements
|
|
6
|
+
|
|
7
|
+
- Added `Dox::HtmlRenderer` for generating HTML documentation from OpenAPI JSON specs. It resolves `$ref` references recursively and delegates HTML generation to an adapter object.
|
|
8
|
+
- `Dox::HtmlRenderer` accepts an overridable `adapter:` argument, so you can provide any renderer object that responds to `build_html(title, spec)`.
|
|
9
|
+
- Added `Dox.config.redoc_version` option to configure the Redoc CDN version used by the default `Dox::RedoclyAdapter` (defaults to `'2.5.1'`)
|
|
10
|
+
- Updated `Dox.config.title` to serve as the fallback title when the OpenAPI spec has no `info.title`
|
|
11
|
+
- Add support for Ruby 4.0
|
|
12
|
+
|
|
13
|
+
### Breaking changes
|
|
14
|
+
|
|
15
|
+
- [BREAKING] Dropped support for Ruby 3.0 and below (Ruby 3.1+ is required)
|
|
16
|
+
|
|
17
|
+
### Good to know
|
|
18
|
+
|
|
19
|
+
- External Node.js renderers (e.g. `redoc-cli`, `@redocly/cli`, `swagger-ui-offline-packager`) are no longer needed. If you only had them in `package.json` for doc generation, you can remove them and use `Dox::HtmlRenderer` instead.
|
|
20
|
+
|
|
21
|
+
## v2.5.0 (2024-12-11)
|
|
22
|
+
|
|
23
|
+
### Enhancements
|
|
24
|
+
|
|
25
|
+
- Add `#check_file_presence_on_init` option to turn off raising error during resource initialization in case a Resource references an MD file under `#desc` that doesn't exist
|
|
26
|
+
|
|
3
27
|
## v2.4.0 (2024-11-21)
|
|
4
28
|
|
|
5
29
|
### Enhancements
|
data/Gemfile
CHANGED
|
@@ -3,6 +3,19 @@ source 'https://rubygems.org'
|
|
|
3
3
|
# Specify your gem's dependencies in dox.gemspec
|
|
4
4
|
gemspec
|
|
5
5
|
|
|
6
|
-
rails_version = ENV['RAILS_VERSION'] || '
|
|
6
|
+
rails_version = ENV['RAILS_VERSION'] || '7.2.0'
|
|
7
7
|
|
|
8
8
|
gem 'activesupport', "~> #{rails_version}"
|
|
9
|
+
|
|
10
|
+
gem 'bundler'
|
|
11
|
+
gem 'codeclimate-test-reporter'
|
|
12
|
+
gem 'json'
|
|
13
|
+
gem 'ostruct'
|
|
14
|
+
gem 'pry-nav'
|
|
15
|
+
gem 'pry-rails'
|
|
16
|
+
gem 'pry-stack_explorer'
|
|
17
|
+
gem 'rake'
|
|
18
|
+
gem 'rspec', '~> 3.0'
|
|
19
|
+
gem 'rubocop-infinum'
|
|
20
|
+
gem 'rubocop-rake'
|
|
21
|
+
gem 'simplecov'
|
data/README.md
CHANGED
|
@@ -14,8 +14,8 @@ Here's a [demo app](https://github.com/infinum/dox-demo).
|
|
|
14
14
|
Add this line to your application's Gemfile:
|
|
15
15
|
|
|
16
16
|
```ruby
|
|
17
|
-
group :test do
|
|
18
|
-
gem 'dox'
|
|
17
|
+
group :development, :test do
|
|
18
|
+
gem 'dox'
|
|
19
19
|
end
|
|
20
20
|
```
|
|
21
21
|
|
|
@@ -51,9 +51,11 @@ Set these optional options in the rails_helper:
|
|
|
51
51
|
| schema_response_fail_file_path | Pathname instance or fullpath string | Json file that contains the default schema of a failed response. |
|
|
52
52
|
| openapi_version | string | Openapi version (default: '3.0.0' ) |
|
|
53
53
|
| api_version | string | Api Version (default: '1.0') |
|
|
54
|
-
| title | string | Documentation title (default: 'API Documentation') |
|
|
54
|
+
| title | string | Documentation title. Used as fallback when the OpenAPI spec has no `info.title`. (default: 'API Documentation') |
|
|
55
55
|
| header_description | Pathname instance or string | Description (header) of the documentation (default: ''). If pathname ends with `.md`, the file is looked in `descriptions_location` folder |
|
|
56
56
|
| headers_whitelist | Array of headers (strings) | Requests and responses will by default list only `Content-Type` header. To list other http headers, you must whitelist them.|
|
|
57
|
+
| redoc_version | string | Redoc version used for HTML rendering (default: '2.5.1') |
|
|
58
|
+
| check_file_presence_on_init | boolean | Option defaults to true. In case an .md file doesn't exist, dox won't wait for the specs to pass before attempting to print the documentation. It will raise an error early during resource initialization. If you're calling Dox.configure multiple times during the spec suite, you might want to set this to false. |
|
|
57
59
|
|
|
58
60
|
Example:
|
|
59
61
|
|
|
@@ -67,6 +69,7 @@ Dox.configure do |config|
|
|
|
67
69
|
config.title = 'API'
|
|
68
70
|
config.api_version = '2.0'
|
|
69
71
|
config.header_description = 'api_description.md'
|
|
72
|
+
config.redoc_version = '2.5.1'
|
|
70
73
|
end
|
|
71
74
|
```
|
|
72
75
|
|
|
@@ -264,21 +267,28 @@ end
|
|
|
264
267
|
### Generate documentation
|
|
265
268
|
Documentation is generated in 2 steps:
|
|
266
269
|
|
|
267
|
-
1.
|
|
268
|
-
```bundle exec rspec --tag apidoc -f Dox::Formatter --order defined --tag dox --out spec/api_doc/v1/schemas/docs.json```
|
|
270
|
+
1. Generate an OpenAPI JSON file from your specs:
|
|
269
271
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
+
```
|
|
273
|
+
bundle exec rspec -f Dox::Formatter --order defined --tag dox --out spec/docs/v1/apispec.json
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
2. Render the OpenAPI JSON file as HTML using the built-in renderer:
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
Dox::HtmlRenderer.new('spec/docs/v1/apispec.json', 'public/api/v1/docs/index.html').render
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`Dox::HtmlRenderer` resolves all `$ref` references in the spec, extracts the title (falling back to `Dox.config.title`), and generates a self-contained HTML file powered by [Redoc](https://github.com/Redocly/redoc). The Redoc JavaScript is loaded from CDN at the version specified by `Dox.config.redoc_version`.
|
|
272
283
|
|
|
284
|
+
No external Node.js dependencies are required.
|
|
273
285
|
|
|
274
286
|
#### Use rake tasks
|
|
275
287
|
It's recommendable to write a few rake tasks to make things easier. Here's an example:
|
|
276
288
|
|
|
277
289
|
```ruby
|
|
278
290
|
namespace :dox do
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
task :json, [:version, :docs_path, :host] => :environment do |_, args|
|
|
291
|
+
task :json, [:version] => :environment do |_, args|
|
|
282
292
|
require 'rspec/core/rake_task'
|
|
283
293
|
version = args[:version] || :v1
|
|
284
294
|
|
|
@@ -291,27 +301,24 @@ namespace :dox do
|
|
|
291
301
|
Rake::Task['api_spec'].invoke
|
|
292
302
|
end
|
|
293
303
|
|
|
294
|
-
task :html, [:version
|
|
304
|
+
task :html, [:version] => :json do |_, args|
|
|
295
305
|
version = args[:version] || :v1
|
|
296
|
-
docs_path =
|
|
306
|
+
docs_path = "api/#{version}/docs"
|
|
307
|
+
spec_path = Rails.root.join("spec/docs/#{version}/apispec.json").to_s
|
|
308
|
+
output_path = Rails.root.join("public/#{docs_path}/index.html").to_s
|
|
297
309
|
|
|
298
|
-
|
|
310
|
+
Dox::HtmlRenderer.new(spec_path, output_path).render
|
|
299
311
|
end
|
|
300
312
|
|
|
301
|
-
task :open, [:version
|
|
313
|
+
task :open, [:version] => :html do |_, args|
|
|
302
314
|
version = args[:version] || :v1
|
|
303
|
-
docs_path =
|
|
315
|
+
docs_path = "api/#{version}/docs"
|
|
304
316
|
|
|
305
317
|
`open public/#{docs_path}/index.html`
|
|
306
318
|
end
|
|
307
319
|
end
|
|
308
320
|
```
|
|
309
321
|
|
|
310
|
-
#### Renderers
|
|
311
|
-
You can render the HTML yourself with ReDoc:
|
|
312
|
-
|
|
313
|
-
- [Redoc](https://github.com/Redocly/redoc)
|
|
314
|
-
|
|
315
322
|
### Common issues
|
|
316
323
|
|
|
317
324
|
You might experience some strange issues when generating the documentation. Here are a few examples of what we've encountered so far.
|
data/Rakefile
CHANGED
data/dox.gemspec
CHANGED
|
@@ -5,36 +5,29 @@ require 'dox/version'
|
|
|
5
5
|
Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'dox'
|
|
7
7
|
spec.version = Dox::VERSION
|
|
8
|
-
spec.authors = ['Melita Kokot', 'Vedran Hrnčić']
|
|
9
|
-
spec.email = ['melita.kokot@gmail.com', 'vrabac266@gmail.com']
|
|
8
|
+
spec.authors = ['Melita Kokot', 'Vedran Hrnčić', 'Marko Ćilimković']
|
|
9
|
+
spec.email = ['melita.kokot@gmail.com', 'vrabac266@gmail.com', 'os.chilim@gmail.com']
|
|
10
10
|
|
|
11
11
|
spec.summary = 'Generates API documentation for rspec in OpenAPI format.'
|
|
12
12
|
spec.homepage = 'https://github.com/infinum/dox'
|
|
13
13
|
spec.license = 'MIT'
|
|
14
14
|
|
|
15
|
-
spec.required_ruby_version = '>=
|
|
15
|
+
spec.required_ruby_version = '>= 3.1.0'
|
|
16
16
|
|
|
17
17
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
18
18
|
# delete this section to allow pushing this gem to any host.
|
|
19
19
|
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
|
|
20
20
|
|
|
21
21
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
22
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
22
23
|
|
|
23
24
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
24
25
|
spec.bindir = 'exe'
|
|
25
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
26
27
|
spec.require_paths = ['lib']
|
|
27
28
|
|
|
28
|
-
spec.
|
|
29
|
-
spec.
|
|
30
|
-
spec.
|
|
31
|
-
spec.
|
|
32
|
-
spec.add_development_dependency 'pry-nav'
|
|
33
|
-
spec.add_development_dependency 'pry-rails'
|
|
34
|
-
spec.add_development_dependency 'pry-stack_explorer'
|
|
35
|
-
spec.add_development_dependency 'rake'
|
|
36
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
37
|
-
spec.add_development_dependency 'rubocop'
|
|
38
|
-
spec.add_development_dependency 'simplecov'
|
|
39
|
-
spec.add_runtime_dependency 'rspec-core'
|
|
29
|
+
spec.add_dependency 'activesupport', '>= 4.0'
|
|
30
|
+
spec.add_dependency 'rack'
|
|
31
|
+
spec.add_dependency 'rexml'
|
|
32
|
+
spec.add_dependency 'rspec-core'
|
|
40
33
|
end
|
data/lib/dox/config.rb
CHANGED
|
@@ -9,7 +9,9 @@ module Dox
|
|
|
9
9
|
attr_accessor :title
|
|
10
10
|
attr_accessor :header_description
|
|
11
11
|
attr_accessor :groups_order
|
|
12
|
+
attr_accessor :redoc_version
|
|
12
13
|
attr_reader :descriptions_location
|
|
14
|
+
attr_writer :check_file_presence_on_init
|
|
13
15
|
|
|
14
16
|
def descriptions_location=(folder_path)
|
|
15
17
|
Array(folder_path).each do |path|
|
|
@@ -37,6 +39,12 @@ module Dox
|
|
|
37
39
|
@schema_response_fail_file_path = file_path
|
|
38
40
|
end
|
|
39
41
|
|
|
42
|
+
def check_file_presence_on_init
|
|
43
|
+
return false if @check_file_presence_on_init == false
|
|
44
|
+
|
|
45
|
+
@check_file_presence_on_init || true
|
|
46
|
+
end
|
|
47
|
+
|
|
40
48
|
def desc_folder_path=(folder_path)
|
|
41
49
|
warn(
|
|
42
50
|
'DEPRECATION WARNING: desc_folder_path will be removed in the next release, please use descriptions_location instead' # rubocop:disable Layout/LineLength
|
data/lib/dox/dsl/resource.rb
CHANGED
|
@@ -16,6 +16,8 @@ module Dox
|
|
|
16
16
|
|
|
17
17
|
raise(Dox::Errors::InvalidResourceError, 'Resource name is required!') if @name.blank?
|
|
18
18
|
raise(Dox::Errors::InvalidResourceError, 'Resource group is required!') if @group.blank?
|
|
19
|
+
|
|
20
|
+
return unless Dox.config.check_file_presence_on_init
|
|
19
21
|
raise(Dox::Errors::InvalidResourceError, "Resource desc #{@desc} is missing!") if desc_file_path.nil?
|
|
20
22
|
end
|
|
21
23
|
|
data/lib/dox/entities/action.rb
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
module Dox
|
|
2
2
|
module Entities
|
|
3
3
|
class Action
|
|
4
|
-
attr_reader :name
|
|
4
|
+
attr_reader :name
|
|
5
|
+
attr_reader :desc
|
|
6
|
+
attr_reader :verb
|
|
7
|
+
attr_reader :path
|
|
8
|
+
attr_reader :resource
|
|
9
|
+
attr_reader :params
|
|
5
10
|
attr_accessor :examples
|
|
6
11
|
|
|
7
12
|
def initialize(details, request)
|
|
@@ -25,7 +30,7 @@ module Dox
|
|
|
25
30
|
def template_path
|
|
26
31
|
path = request.path.dup.presence || request.fullpath.split('?').first
|
|
27
32
|
path_params.each do |key, value|
|
|
28
|
-
path.sub!(%r{
|
|
33
|
+
path.sub!(%r{/#{value}(/|$)}, "/{#{key}}\\1")
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
path
|
|
@@ -64,7 +69,7 @@ module Dox
|
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
def guess_param_type(param)
|
|
67
|
-
if param =~ /^\d+$/
|
|
72
|
+
if param.to_s =~ /^\d+$/
|
|
68
73
|
:number
|
|
69
74
|
else
|
|
70
75
|
:string
|
data/lib/dox/entities/example.rb
CHANGED
|
@@ -3,7 +3,11 @@ module Dox
|
|
|
3
3
|
class Example
|
|
4
4
|
extend Forwardable
|
|
5
5
|
|
|
6
|
-
attr_reader :desc
|
|
6
|
+
attr_reader :desc
|
|
7
|
+
attr_reader :name
|
|
8
|
+
attr_reader :request_schema
|
|
9
|
+
attr_reader :response_schema_success
|
|
10
|
+
attr_reader :response_schema_fail
|
|
7
11
|
|
|
8
12
|
def_delegator :request, :method, :request_method
|
|
9
13
|
def_delegator :response, :status, :response_status
|
|
@@ -68,7 +72,7 @@ module Dox
|
|
|
68
72
|
|
|
69
73
|
def formatter(content_type)
|
|
70
74
|
case content_type
|
|
71
|
-
when %r{application
|
|
75
|
+
when %r{application/.*json}
|
|
72
76
|
Dox::Formatters::Json
|
|
73
77
|
when /xml/
|
|
74
78
|
Dox::Formatters::Xml
|
|
@@ -84,15 +88,16 @@ module Dox
|
|
|
84
88
|
request.path.presence || request.fullpath.split('?')[0]
|
|
85
89
|
end
|
|
86
90
|
|
|
87
|
-
attr_reader :request
|
|
91
|
+
attr_reader :request
|
|
92
|
+
attr_reader :response
|
|
88
93
|
|
|
89
94
|
def filter_headers(obj)
|
|
90
|
-
headers_whitelist.
|
|
95
|
+
headers_whitelist.filter_map do |header|
|
|
91
96
|
header_val = obj.headers[header]
|
|
92
97
|
next if header_val.blank?
|
|
93
98
|
|
|
94
99
|
[header, header_val]
|
|
95
|
-
end
|
|
100
|
+
end
|
|
96
101
|
end
|
|
97
102
|
|
|
98
103
|
def headers_whitelist
|
data/lib/dox/formatters/base.rb
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Dox
|
|
2
|
+
class HtmlRenderer
|
|
3
|
+
def initialize(spec_path, output_path, adapter: Dox::RedoclyAdapter.new)
|
|
4
|
+
@spec_path = spec_path
|
|
5
|
+
@output_path = output_path
|
|
6
|
+
@adapter = adapter
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render
|
|
10
|
+
spec = JSON.load_file(spec_path)
|
|
11
|
+
resolved = resolve_file_refs(spec, ::File.dirname(spec_path))
|
|
12
|
+
title = resolved.dig('info', 'title') || Dox.config.title
|
|
13
|
+
|
|
14
|
+
FileUtils.mkdir_p(::File.dirname(output_path))
|
|
15
|
+
::File.write(output_path, adapter.build_html(title, resolved))
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
attr_reader :spec_path
|
|
21
|
+
attr_reader :output_path
|
|
22
|
+
attr_reader :adapter
|
|
23
|
+
|
|
24
|
+
def resolve_file_refs(obj, base_dir) # rubocop:disable Metrics/MethodLength
|
|
25
|
+
case obj
|
|
26
|
+
when Hash
|
|
27
|
+
if obj.key?('$ref') && !obj['$ref'].start_with?('#')
|
|
28
|
+
load_schema(obj['$ref'], base_dir)
|
|
29
|
+
else
|
|
30
|
+
obj.transform_values { |v| resolve_file_refs(v, base_dir) }
|
|
31
|
+
end
|
|
32
|
+
when Array
|
|
33
|
+
obj.map { |item| resolve_file_refs(item, base_dir) }
|
|
34
|
+
else
|
|
35
|
+
obj
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def load_schema(ref_path, base_dir)
|
|
40
|
+
full_path = ::File.expand_path(ref_path, base_dir)
|
|
41
|
+
schema = JSON.load_file(full_path)
|
|
42
|
+
resolved = resolve_file_refs(schema, ::File.dirname(full_path))
|
|
43
|
+
resolve_internal_refs(resolved)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Internal $refs like "#/path/to/thing" are JSON pointers into the
|
|
47
|
+
# same document. Once a file is inlined into the spec, the root
|
|
48
|
+
# changes and these pointers break. This resolves them while the
|
|
49
|
+
# file's own root is still available.
|
|
50
|
+
def resolve_internal_refs(schema)
|
|
51
|
+
replace_json_pointer_refs(schema, root: schema)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def replace_json_pointer_refs(obj, root:) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
55
|
+
case obj
|
|
56
|
+
when Hash
|
|
57
|
+
if obj.key?('$ref') && obj['$ref'].start_with?('#/')
|
|
58
|
+
keys = obj['$ref'].delete_prefix('#/').split('/')
|
|
59
|
+
target = root.dig(*keys)
|
|
60
|
+
target ? replace_json_pointer_refs(target, root: root) : obj
|
|
61
|
+
else
|
|
62
|
+
obj.transform_values { |v| replace_json_pointer_refs(v, root: root) }
|
|
63
|
+
end
|
|
64
|
+
when Array
|
|
65
|
+
obj.map { |item| replace_json_pointer_refs(item, root: root) }
|
|
66
|
+
else
|
|
67
|
+
obj
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -27,7 +27,7 @@ module Dox
|
|
|
27
27
|
|
|
28
28
|
def formatted_body(body_str, content_type)
|
|
29
29
|
case content_type
|
|
30
|
-
when %r{application
|
|
30
|
+
when %r{application/.*json}
|
|
31
31
|
JSON.parse(body_str)
|
|
32
32
|
when /xml/
|
|
33
33
|
pretty_xml(body_str)
|
|
@@ -48,7 +48,11 @@ module Dox
|
|
|
48
48
|
def format_desc(description)
|
|
49
49
|
desc = description
|
|
50
50
|
desc = '' if desc.nil?
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
if desc.end_with?('.md')
|
|
53
|
+
desc = read_file(desc)
|
|
54
|
+
raise "#{description} file is missing!" if desc.nil?
|
|
55
|
+
end
|
|
52
56
|
|
|
53
57
|
desc
|
|
54
58
|
end
|
|
@@ -27,18 +27,14 @@ module Dox
|
|
|
27
27
|
openapi: Dox.config.openapi_version || '3.0.0',
|
|
28
28
|
info: {
|
|
29
29
|
title: Dox.config.title || 'API Documentation',
|
|
30
|
-
description:
|
|
30
|
+
description: adjusted_description,
|
|
31
31
|
version: Dox.config.api_version || '1.0'
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def acquire_desc(path)
|
|
41
|
-
read_file(path)
|
|
36
|
+
def adjusted_description
|
|
37
|
+
format_desc(Dox.config.header_description)
|
|
42
38
|
end
|
|
43
39
|
|
|
44
40
|
def group_printer
|
|
@@ -79,7 +79,7 @@ module Dox
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def add_headers(body)
|
|
82
|
-
body['headers'] =
|
|
82
|
+
body['headers'] = example.response_headers.to_h { |key, value| [key, { description: value }] }
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Dox
|
|
2
|
+
class RedoclyAdapter
|
|
3
|
+
DEFAULT_REDOC_VERSION = '2.5.1'.freeze
|
|
4
|
+
|
|
5
|
+
def build_html(title, spec)
|
|
6
|
+
<<~HTML
|
|
7
|
+
<!DOCTYPE html>
|
|
8
|
+
<html>
|
|
9
|
+
<head>
|
|
10
|
+
<meta charset="utf-8"/>
|
|
11
|
+
<title>#{title}</title>
|
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
13
|
+
<style>body { margin: 0; padding: 0; }</style>
|
|
14
|
+
</head>
|
|
15
|
+
<body>
|
|
16
|
+
<div id="redoc"></div>
|
|
17
|
+
<script src="https://cdn.redocly.com/redoc/v#{redoc_version}/bundles/redoc.standalone.js"></script>
|
|
18
|
+
<script>
|
|
19
|
+
Redoc.init(#{JSON.generate(spec)}, {}, document.getElementById('redoc'));
|
|
20
|
+
</script>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
23
|
+
HTML
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def redoc_version
|
|
29
|
+
Dox.config.redoc_version || DEFAULT_REDOC_VERSION
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/dox/version.rb
CHANGED
data/lib/dox.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
require 'active_support/concern'
|
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
require 'active_support/core_ext/object/to_query'
|
|
2
5
|
require 'active_support/core_ext/string'
|
|
3
6
|
require 'forwardable'
|
|
4
7
|
|
|
@@ -31,12 +34,15 @@ require 'dox/printers/example_request_printer'
|
|
|
31
34
|
require 'dox/printers/example_response_printer'
|
|
32
35
|
require 'dox/printers/resource_group_printer'
|
|
33
36
|
require 'dox/printers/resource_printer'
|
|
37
|
+
require 'dox/redocly_adapter'
|
|
38
|
+
require 'dox/html_renderer'
|
|
34
39
|
require 'dox/util/http'
|
|
35
40
|
require 'dox/util/file'
|
|
36
41
|
require 'dox/version'
|
|
37
42
|
|
|
38
43
|
module Dox
|
|
39
|
-
Error
|
|
44
|
+
class Error < StandardError
|
|
45
|
+
end
|
|
40
46
|
|
|
41
47
|
def self.configure
|
|
42
48
|
yield(config) if block_given?
|
metadata
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Melita Kokot
|
|
8
8
|
- Vedran Hrnčić
|
|
9
|
-
|
|
9
|
+
- Marko Ćilimković
|
|
10
|
+
autorequire:
|
|
10
11
|
bindir: exe
|
|
11
12
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
+
date: 2026-03-02 00:00:00.000000000 Z
|
|
13
14
|
dependencies:
|
|
14
15
|
- !ruby/object:Gem::Dependency
|
|
15
16
|
name: activesupport
|
|
@@ -26,125 +27,13 @@ dependencies:
|
|
|
26
27
|
- !ruby/object:Gem::Version
|
|
27
28
|
version: '4.0'
|
|
28
29
|
- !ruby/object:Gem::Dependency
|
|
29
|
-
name:
|
|
30
|
+
name: rack
|
|
30
31
|
requirement: !ruby/object:Gem::Requirement
|
|
31
32
|
requirements:
|
|
32
33
|
- - ">="
|
|
33
34
|
- !ruby/object:Gem::Version
|
|
34
35
|
version: '0'
|
|
35
|
-
type: :
|
|
36
|
-
prerelease: false
|
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
-
requirements:
|
|
39
|
-
- - ">="
|
|
40
|
-
- !ruby/object:Gem::Version
|
|
41
|
-
version: '0'
|
|
42
|
-
- !ruby/object:Gem::Dependency
|
|
43
|
-
name: codeclimate-test-reporter
|
|
44
|
-
requirement: !ruby/object:Gem::Requirement
|
|
45
|
-
requirements:
|
|
46
|
-
- - ">="
|
|
47
|
-
- !ruby/object:Gem::Version
|
|
48
|
-
version: '0'
|
|
49
|
-
type: :development
|
|
50
|
-
prerelease: false
|
|
51
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
-
requirements:
|
|
53
|
-
- - ">="
|
|
54
|
-
- !ruby/object:Gem::Version
|
|
55
|
-
version: '0'
|
|
56
|
-
- !ruby/object:Gem::Dependency
|
|
57
|
-
name: json
|
|
58
|
-
requirement: !ruby/object:Gem::Requirement
|
|
59
|
-
requirements:
|
|
60
|
-
- - ">="
|
|
61
|
-
- !ruby/object:Gem::Version
|
|
62
|
-
version: '0'
|
|
63
|
-
type: :development
|
|
64
|
-
prerelease: false
|
|
65
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
-
requirements:
|
|
67
|
-
- - ">="
|
|
68
|
-
- !ruby/object:Gem::Version
|
|
69
|
-
version: '0'
|
|
70
|
-
- !ruby/object:Gem::Dependency
|
|
71
|
-
name: pry-nav
|
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
|
73
|
-
requirements:
|
|
74
|
-
- - ">="
|
|
75
|
-
- !ruby/object:Gem::Version
|
|
76
|
-
version: '0'
|
|
77
|
-
type: :development
|
|
78
|
-
prerelease: false
|
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
-
requirements:
|
|
81
|
-
- - ">="
|
|
82
|
-
- !ruby/object:Gem::Version
|
|
83
|
-
version: '0'
|
|
84
|
-
- !ruby/object:Gem::Dependency
|
|
85
|
-
name: pry-rails
|
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
|
87
|
-
requirements:
|
|
88
|
-
- - ">="
|
|
89
|
-
- !ruby/object:Gem::Version
|
|
90
|
-
version: '0'
|
|
91
|
-
type: :development
|
|
92
|
-
prerelease: false
|
|
93
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
94
|
-
requirements:
|
|
95
|
-
- - ">="
|
|
96
|
-
- !ruby/object:Gem::Version
|
|
97
|
-
version: '0'
|
|
98
|
-
- !ruby/object:Gem::Dependency
|
|
99
|
-
name: pry-stack_explorer
|
|
100
|
-
requirement: !ruby/object:Gem::Requirement
|
|
101
|
-
requirements:
|
|
102
|
-
- - ">="
|
|
103
|
-
- !ruby/object:Gem::Version
|
|
104
|
-
version: '0'
|
|
105
|
-
type: :development
|
|
106
|
-
prerelease: false
|
|
107
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
108
|
-
requirements:
|
|
109
|
-
- - ">="
|
|
110
|
-
- !ruby/object:Gem::Version
|
|
111
|
-
version: '0'
|
|
112
|
-
- !ruby/object:Gem::Dependency
|
|
113
|
-
name: rake
|
|
114
|
-
requirement: !ruby/object:Gem::Requirement
|
|
115
|
-
requirements:
|
|
116
|
-
- - ">="
|
|
117
|
-
- !ruby/object:Gem::Version
|
|
118
|
-
version: '0'
|
|
119
|
-
type: :development
|
|
120
|
-
prerelease: false
|
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
122
|
-
requirements:
|
|
123
|
-
- - ">="
|
|
124
|
-
- !ruby/object:Gem::Version
|
|
125
|
-
version: '0'
|
|
126
|
-
- !ruby/object:Gem::Dependency
|
|
127
|
-
name: rspec
|
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
|
129
|
-
requirements:
|
|
130
|
-
- - "~>"
|
|
131
|
-
- !ruby/object:Gem::Version
|
|
132
|
-
version: '3.0'
|
|
133
|
-
type: :development
|
|
134
|
-
prerelease: false
|
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
136
|
-
requirements:
|
|
137
|
-
- - "~>"
|
|
138
|
-
- !ruby/object:Gem::Version
|
|
139
|
-
version: '3.0'
|
|
140
|
-
- !ruby/object:Gem::Dependency
|
|
141
|
-
name: rubocop
|
|
142
|
-
requirement: !ruby/object:Gem::Requirement
|
|
143
|
-
requirements:
|
|
144
|
-
- - ">="
|
|
145
|
-
- !ruby/object:Gem::Version
|
|
146
|
-
version: '0'
|
|
147
|
-
type: :development
|
|
36
|
+
type: :runtime
|
|
148
37
|
prerelease: false
|
|
149
38
|
version_requirements: !ruby/object:Gem::Requirement
|
|
150
39
|
requirements:
|
|
@@ -152,13 +41,13 @@ dependencies:
|
|
|
152
41
|
- !ruby/object:Gem::Version
|
|
153
42
|
version: '0'
|
|
154
43
|
- !ruby/object:Gem::Dependency
|
|
155
|
-
name:
|
|
44
|
+
name: rexml
|
|
156
45
|
requirement: !ruby/object:Gem::Requirement
|
|
157
46
|
requirements:
|
|
158
47
|
- - ">="
|
|
159
48
|
- !ruby/object:Gem::Version
|
|
160
49
|
version: '0'
|
|
161
|
-
type: :
|
|
50
|
+
type: :runtime
|
|
162
51
|
prerelease: false
|
|
163
52
|
version_requirements: !ruby/object:Gem::Requirement
|
|
164
53
|
requirements:
|
|
@@ -179,15 +68,17 @@ dependencies:
|
|
|
179
68
|
- - ">="
|
|
180
69
|
- !ruby/object:Gem::Version
|
|
181
70
|
version: '0'
|
|
182
|
-
description:
|
|
71
|
+
description:
|
|
183
72
|
email:
|
|
184
73
|
- melita.kokot@gmail.com
|
|
185
74
|
- vrabac266@gmail.com
|
|
75
|
+
- os.chilim@gmail.com
|
|
186
76
|
executables:
|
|
187
77
|
- dox
|
|
188
78
|
extensions: []
|
|
189
79
|
extra_rdoc_files: []
|
|
190
80
|
files:
|
|
81
|
+
- ".github/workflows/ci.yml"
|
|
191
82
|
- ".gitignore"
|
|
192
83
|
- ".rspec"
|
|
193
84
|
- ".rubocop.yml"
|
|
@@ -227,6 +118,7 @@ files:
|
|
|
227
118
|
- lib/dox/formatters/multipart.rb
|
|
228
119
|
- lib/dox/formatters/plain.rb
|
|
229
120
|
- lib/dox/formatters/xml.rb
|
|
121
|
+
- lib/dox/html_renderer.rb
|
|
230
122
|
- lib/dox/printers/action_printer.rb
|
|
231
123
|
- lib/dox/printers/base_printer.rb
|
|
232
124
|
- lib/dox/printers/document_printer.rb
|
|
@@ -234,6 +126,7 @@ files:
|
|
|
234
126
|
- lib/dox/printers/example_response_printer.rb
|
|
235
127
|
- lib/dox/printers/resource_group_printer.rb
|
|
236
128
|
- lib/dox/printers/resource_printer.rb
|
|
129
|
+
- lib/dox/redocly_adapter.rb
|
|
237
130
|
- lib/dox/util/file.rb
|
|
238
131
|
- lib/dox/util/http.rb
|
|
239
132
|
- lib/dox/version.rb
|
|
@@ -242,7 +135,8 @@ licenses:
|
|
|
242
135
|
- MIT
|
|
243
136
|
metadata:
|
|
244
137
|
allowed_push_host: https://rubygems.org
|
|
245
|
-
|
|
138
|
+
rubygems_mfa_required: 'true'
|
|
139
|
+
post_install_message:
|
|
246
140
|
rdoc_options: []
|
|
247
141
|
require_paths:
|
|
248
142
|
- lib
|
|
@@ -250,15 +144,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
250
144
|
requirements:
|
|
251
145
|
- - ">="
|
|
252
146
|
- !ruby/object:Gem::Version
|
|
253
|
-
version:
|
|
147
|
+
version: 3.1.0
|
|
254
148
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
255
149
|
requirements:
|
|
256
150
|
- - ">="
|
|
257
151
|
- !ruby/object:Gem::Version
|
|
258
152
|
version: '0'
|
|
259
153
|
requirements: []
|
|
260
|
-
rubygems_version: 3.
|
|
261
|
-
signing_key:
|
|
154
|
+
rubygems_version: 3.3.27
|
|
155
|
+
signing_key:
|
|
262
156
|
specification_version: 4
|
|
263
157
|
summary: Generates API documentation for rspec in OpenAPI format.
|
|
264
158
|
test_files: []
|