dox 2.5.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 +18 -0
- data/Gemfile +14 -1
- data/README.md +26 -20
- data/Rakefile +7 -1
- data/dox.gemspec +8 -15
- data/lib/dox/config.rb +1 -0
- data/lib/dox/dsl/resource.rb +2 -3
- 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 +1 -1
- 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,23 @@
|
|
|
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
|
+
|
|
3
21
|
## v2.5.0 (2024-12-11)
|
|
4
22
|
|
|
5
23
|
### 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,10 @@ 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') |
|
|
57
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. |
|
|
58
59
|
|
|
59
60
|
Example:
|
|
@@ -68,6 +69,7 @@ Dox.configure do |config|
|
|
|
68
69
|
config.title = 'API'
|
|
69
70
|
config.api_version = '2.0'
|
|
70
71
|
config.header_description = 'api_description.md'
|
|
72
|
+
config.redoc_version = '2.5.1'
|
|
71
73
|
end
|
|
72
74
|
```
|
|
73
75
|
|
|
@@ -265,21 +267,28 @@ end
|
|
|
265
267
|
### Generate documentation
|
|
266
268
|
Documentation is generated in 2 steps:
|
|
267
269
|
|
|
268
|
-
1.
|
|
269
|
-
```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:
|
|
270
271
|
|
|
271
|
-
|
|
272
|
-
|
|
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`.
|
|
273
283
|
|
|
284
|
+
No external Node.js dependencies are required.
|
|
274
285
|
|
|
275
286
|
#### Use rake tasks
|
|
276
287
|
It's recommendable to write a few rake tasks to make things easier. Here's an example:
|
|
277
288
|
|
|
278
289
|
```ruby
|
|
279
290
|
namespace :dox do
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
task :json, [:version, :docs_path, :host] => :environment do |_, args|
|
|
291
|
+
task :json, [:version] => :environment do |_, args|
|
|
283
292
|
require 'rspec/core/rake_task'
|
|
284
293
|
version = args[:version] || :v1
|
|
285
294
|
|
|
@@ -292,27 +301,24 @@ namespace :dox do
|
|
|
292
301
|
Rake::Task['api_spec'].invoke
|
|
293
302
|
end
|
|
294
303
|
|
|
295
|
-
task :html, [:version
|
|
304
|
+
task :html, [:version] => :json do |_, args|
|
|
296
305
|
version = args[:version] || :v1
|
|
297
|
-
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
|
|
298
309
|
|
|
299
|
-
|
|
310
|
+
Dox::HtmlRenderer.new(spec_path, output_path).render
|
|
300
311
|
end
|
|
301
312
|
|
|
302
|
-
task :open, [:version
|
|
313
|
+
task :open, [:version] => :html do |_, args|
|
|
303
314
|
version = args[:version] || :v1
|
|
304
|
-
docs_path =
|
|
315
|
+
docs_path = "api/#{version}/docs"
|
|
305
316
|
|
|
306
317
|
`open public/#{docs_path}/index.html`
|
|
307
318
|
end
|
|
308
319
|
end
|
|
309
320
|
```
|
|
310
321
|
|
|
311
|
-
#### Renderers
|
|
312
|
-
You can render the HTML yourself with ReDoc:
|
|
313
|
-
|
|
314
|
-
- [Redoc](https://github.com/Redocly/redoc)
|
|
315
|
-
|
|
316
322
|
### Common issues
|
|
317
323
|
|
|
318
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
data/lib/dox/dsl/resource.rb
CHANGED
|
@@ -17,9 +17,8 @@ module Dox
|
|
|
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
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
20
|
+
return unless Dox.config.check_file_presence_on_init
|
|
21
|
+
raise(Dox::Errors::InvalidResourceError, "Resource desc #{@desc} is missing!") if desc_file_path.nil?
|
|
23
22
|
end
|
|
24
23
|
|
|
25
24
|
def config
|
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
|
|
@@ -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: []
|