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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28307d7bc11d4b35d5951f89c855b98af58877cb956a8f638a8541b9358d239d
4
- data.tar.gz: 62e8c8228e9390adc964fce294ea2c83017a1da64de73d959d30588e22010317
3
+ metadata.gz: 9a254b169809b99600afcc0dae0e46f55f6214604ceab941215dee84c48d17af
4
+ data.tar.gz: a3172985b3aeeff16496a2b192808c90429519ac79c4ddb2b2a4b36f7cbc21f4
5
5
  SHA512:
6
- metadata.gz: 05cc87faaf0602cb9f01bc3cf72ad7d4a98c3db5a331bad7380746f515eeea67f5143763f31107cb3d5aa44a884a62206f669138c0901f01090dcd4930a3199e
7
- data.tar.gz: 85bce8dbc8b87d9244db98d449c01e7b26fce507bcdbf1eafaa454c6f554a8562bb68d5e1d949bb28f7b3dc5ac62dfc1f50b246f1619e09a36cf8d1d99aa8929
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
- LineLength:
2
- Max: 120
1
+ inherit_gem:
2
+ rubocop-infinum: rubocop.yml
3
3
 
4
- Documentation:
5
- Enabled: False
4
+ plugins:
5
+ - rubocop-infinum
6
+ - rubocop-rake
6
7
 
7
- WordArray:
8
- Enabled: False
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
- BlockLength:
14
- Max: 250
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
- Gemspec/RequiredRubyVersion:
83
+ RSpec/LeakyConstantDeclaration:
17
84
  Enabled: false
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.7
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.0.2'
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', require: false
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. generate OpenApi json file:
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
- 2. render HTML with Redoc:
271
- ```redoc-cli bundle -o public/api/docs/v2/docs.html spec/api_doc/v1/schemas/docs.json```
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
- desc 'Generate API documentation markdown'
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, :docs_path, :host] => :json do |_, args|
304
+ task :html, [:version] => :json do |_, args|
295
305
  version = args[:version] || :v1
296
- docs_path = args[:docs_path] || "api/#{version}/docs"
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
- `yarn run redoc-cli bundle -o public/#{docs_path}/index.html spec/docs/#{version}/apispec.json`
310
+ Dox::HtmlRenderer.new(spec_path, output_path).render
299
311
  end
300
312
 
301
- task :open, [:version, :docs_path, :host] => :html do |_, args|
313
+ task :open, [:version] => :html do |_, args|
302
314
  version = args[:version] || :v1
303
- docs_path = args[:docs_path] || "api/#{version}/docs"
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
@@ -1,6 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task default: :spec
8
+ require 'rubocop/rake_task'
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: [:spec, :rubocop]
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 = '>= 2.0.0'
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.add_runtime_dependency 'activesupport', '>= 4.0'
29
- spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'codeclimate-test-reporter'
31
- spec.add_development_dependency 'json'
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
@@ -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
 
@@ -1,7 +1,12 @@
1
1
  module Dox
2
2
  module Entities
3
3
  class Action
4
- attr_reader :name, :desc, :verb, :path, :resource, :params
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{\/#{value}(\/|$)}, "/{#{key}}\\1")
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
@@ -3,7 +3,11 @@ module Dox
3
3
  class Example
4
4
  extend Forwardable
5
5
 
6
- attr_reader :desc, :name, :request_schema, :response_schema_success, :response_schema_fail
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\/.*json}
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, :response
91
+ attr_reader :request
92
+ attr_reader :response
88
93
 
89
94
  def filter_headers(obj)
90
- headers_whitelist.map do |header|
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.compact
100
+ end
96
101
  end
97
102
 
98
103
  def headers_whitelist
@@ -1,7 +1,9 @@
1
1
  module Dox
2
2
  module Entities
3
3
  class Resource
4
- attr_reader :name, :desc, :group
4
+ attr_reader :name
5
+ attr_reader :desc
6
+ attr_reader :group
5
7
  attr_accessor :actions
6
8
 
7
9
  def initialize(details)
@@ -2,7 +2,8 @@ module Dox
2
2
  module Entities
3
3
  class ResourceGroup
4
4
  attr_reader :name
5
- attr_accessor :desc, :resources
5
+ attr_accessor :desc
6
+ attr_accessor :resources
6
7
 
7
8
  def initialize(details)
8
9
  @name = details[:resource_group_name]
@@ -13,7 +13,8 @@ module Dox
13
13
 
14
14
  private
15
15
 
16
- attr_reader :http_env, :body
16
+ attr_reader :http_env
17
+ attr_reader :body
17
18
  end
18
19
  end
19
20
  end
@@ -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
@@ -13,7 +13,8 @@ module Dox
13
13
 
14
14
  private
15
15
 
16
- attr_accessor :action, :action_hash
16
+ attr_accessor :action
17
+ attr_accessor :action_hash
17
18
 
18
19
  def add_action
19
20
  action_hash['summary'] = action.name
@@ -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\/.*json}
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
- desc = read_file(desc) if desc.end_with?('.md')
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: adjust_description(Dox.config.header_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 adjust_description(description)
37
- description.end_with?('.md') ? acquire_desc(description) : description
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'] = Hash[example.response_headers.map { |key, value| [key, { description: value }] }]
82
+ body['headers'] = example.response_headers.to_h { |key, value| [key, { description: value }] }
83
83
  end
84
84
  end
85
85
  end
@@ -5,7 +5,7 @@ module Dox
5
5
  self.resource_group = resource_group
6
6
  add_resource_group
7
7
 
8
- resource_group.resources.each do |_, resource|
8
+ resource_group.resources.each_value do |resource|
9
9
  resource_printer.print(resource)
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Dox
5
5
  self.resource = resource
6
6
  add_resources
7
7
 
8
- resource.actions.each do |_, action|
8
+ resource.actions.each_value do |action|
9
9
  action_printer.print(action)
10
10
  end
11
11
  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
@@ -1,3 +1,3 @@
1
1
  module Dox
2
- VERSION = '2.4.0'.freeze
2
+ VERSION = '3.0.0'.freeze
3
3
  end
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 = Class.new(StandardError)
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: 2.4.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Melita Kokot
8
8
  - Vedran Hrnčić
9
- autorequire:
9
+ - Marko Ćilimković
10
+ autorequire:
10
11
  bindir: exe
11
12
  cert_chain: []
12
- date: 2024-11-21 00:00:00.000000000 Z
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: bundler
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: :development
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: simplecov
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: :development
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
- post_install_message:
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: 2.0.0
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.0.3.1
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: []