oas_rails 0.2.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +10 -1
- data/app/controllers/oas_rails/oas_rails_controller.rb +1 -1
- data/lib/generators/oas_rails/config/templates/oas_rails_initializer.rb +11 -0
- data/lib/oas_rails/builders/content_builder.rb +55 -0
- data/lib/oas_rails/builders/operation_builder.rb +32 -0
- data/lib/oas_rails/builders/parameter_builder.rb +28 -0
- data/lib/oas_rails/builders/parameters_builder.rb +39 -0
- data/lib/oas_rails/builders/path_item_builder.rb +22 -0
- data/lib/oas_rails/builders/request_body_builder.rb +60 -0
- data/lib/oas_rails/builders/response_builder.rb +40 -0
- data/lib/oas_rails/builders/responses_builder.rb +58 -0
- data/lib/oas_rails/configuration.rb +25 -5
- data/lib/oas_rails/esquema_builder.rb +37 -0
- data/lib/oas_rails/extractors/oas_route_extractor.rb +66 -0
- data/lib/oas_rails/extractors/render_response_extractor.rb +148 -0
- data/lib/oas_rails/extractors/route_extractor.rb +125 -0
- data/lib/oas_rails/oas_route.rb +1 -99
- data/lib/oas_rails/spec/components.rb +85 -0
- data/lib/oas_rails/spec/contact.rb +18 -0
- data/lib/oas_rails/spec/hashable.rb +39 -0
- data/lib/oas_rails/{info.rb → spec/info.rb} +30 -24
- data/lib/oas_rails/spec/license.rb +18 -0
- data/lib/oas_rails/spec/media_type.rb +84 -0
- data/lib/oas_rails/spec/operation.rb +25 -0
- data/lib/oas_rails/spec/parameter.rb +34 -0
- data/lib/oas_rails/spec/path_item.rb +33 -0
- data/lib/oas_rails/spec/paths.rb +26 -0
- data/lib/oas_rails/spec/reference.rb +16 -0
- data/lib/oas_rails/spec/request_body.rb +21 -0
- data/lib/oas_rails/spec/response.rb +20 -0
- data/lib/oas_rails/spec/responses.rb +25 -0
- data/lib/oas_rails/spec/server.rb +17 -0
- data/lib/oas_rails/spec/specable.rb +51 -0
- data/lib/oas_rails/spec/specification.rb +50 -0
- data/lib/oas_rails/spec/tag.rb +18 -0
- data/lib/oas_rails/utils.rb +39 -0
- data/lib/oas_rails/version.rb +1 -1
- data/lib/oas_rails.rb +47 -26
- metadata +32 -18
- data/lib/oas_rails/contact.rb +0 -12
- data/lib/oas_rails/license.rb +0 -11
- data/lib/oas_rails/media_type.rb +0 -76
- data/lib/oas_rails/oas_base.rb +0 -30
- data/lib/oas_rails/operation.rb +0 -134
- data/lib/oas_rails/parameter.rb +0 -47
- data/lib/oas_rails/path_item.rb +0 -25
- data/lib/oas_rails/paths.rb +0 -19
- data/lib/oas_rails/request_body.rb +0 -29
- data/lib/oas_rails/response.rb +0 -12
- data/lib/oas_rails/responses.rb +0 -20
- data/lib/oas_rails/route_extractor.rb +0 -119
- data/lib/oas_rails/server.rb +0 -10
- data/lib/oas_rails/specification.rb +0 -72
- data/lib/oas_rails/tag.rb +0 -17
data/lib/oas_rails/license.rb
DELETED
data/lib/oas_rails/media_type.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class MediaType < OasBase
|
3
|
-
attr_accessor :schema, :example, :examples, :encoding
|
4
|
-
|
5
|
-
def initialize(schema:, **kwargs)
|
6
|
-
super()
|
7
|
-
@schema = schema
|
8
|
-
@example = kwargs[:example] || {}
|
9
|
-
@examples = kwargs[:examples] || []
|
10
|
-
end
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def from_model_class(klass:, examples: {})
|
14
|
-
return unless klass.ancestors.include? ActiveRecord::Base
|
15
|
-
|
16
|
-
model_schema = Esquema::Builder.new(klass).build_schema.as_json
|
17
|
-
model_schema["required"] = []
|
18
|
-
schema = { type: "object", properties: { klass.to_s.downcase => model_schema } }
|
19
|
-
examples.merge!(search_for_examples_in_tests(klass:))
|
20
|
-
new(media_type: "", schema:, examples:)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Searches for examples in test files based on the provided class and test framework.
|
24
|
-
#
|
25
|
-
# This method handles different test frameworks to fetch examples for the given class.
|
26
|
-
# Currently, it supports FactoryBot and fixtures.
|
27
|
-
#
|
28
|
-
# @param klass [Class] the class to search examples for.
|
29
|
-
# @param utils [Module] a utility module that provides the `detect_test_framework` method. Defaults to `Utils`.
|
30
|
-
# @return [Hash] a hash containing examples data or an empty hash if no examples are found.
|
31
|
-
# @example Usage with FactoryBot
|
32
|
-
# search_for_examples_in_tests(klass: User)
|
33
|
-
#
|
34
|
-
# @example Usage with fixtures
|
35
|
-
# search_for_examples_in_tests(klass: Project)
|
36
|
-
#
|
37
|
-
# @example Usage with a custom utils module
|
38
|
-
# custom_utils = Module.new do
|
39
|
-
# def self.detect_test_framework
|
40
|
-
# :factory_bot
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
# search_for_examples_in_tests(klass: User, utils: custom_utils)
|
44
|
-
def search_for_examples_in_tests(klass:, utils: Utils)
|
45
|
-
case utils.detect_test_framework
|
46
|
-
when :factory_bot
|
47
|
-
{}
|
48
|
-
# TODO: create examples with FactoryBot
|
49
|
-
when :fixtures
|
50
|
-
fixture_file = Rails.root.join('test', 'fixtures', "#{klass.to_s.pluralize.downcase}.yml")
|
51
|
-
|
52
|
-
begin
|
53
|
-
fixture_data = YAML.load_file(fixture_file).with_indifferent_access
|
54
|
-
rescue Errno::ENOENT
|
55
|
-
return {}
|
56
|
-
end
|
57
|
-
|
58
|
-
fixture_data.transform_values { |attributes| { value: { klass.to_s.downcase => attributes } } }
|
59
|
-
else
|
60
|
-
{}
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def tags_to_examples(tags:)
|
65
|
-
tags.each_with_object({}).with_index(1) do |(example, result), _index|
|
66
|
-
key = example.text.downcase.gsub(' ', '_')
|
67
|
-
value = {
|
68
|
-
"summary" => example.text,
|
69
|
-
"value" => example.content
|
70
|
-
}
|
71
|
-
result[key] = value
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
data/lib/oas_rails/oas_base.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class OasBase
|
3
|
-
def to_spec
|
4
|
-
hash = {}
|
5
|
-
instance_variables.each do |var|
|
6
|
-
key = var.to_s.delete('@')
|
7
|
-
camel_case_key = key.camelize(:lower).to_sym
|
8
|
-
value = instance_variable_get(var)
|
9
|
-
|
10
|
-
processed_value = if value.respond_to?(:to_spec)
|
11
|
-
value.to_spec
|
12
|
-
else
|
13
|
-
value
|
14
|
-
end
|
15
|
-
|
16
|
-
# hash[camel_case_key] = processed_value unless (processed_value.is_a?(Hash) || processed_value.is_a?(Array)) && processed_value.empty?
|
17
|
-
hash[camel_case_key] = processed_value
|
18
|
-
end
|
19
|
-
hash
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def snake_to_camel(snake_str)
|
25
|
-
words = snake_str.to_s.split('_')
|
26
|
-
words[1..].map!(&:capitalize)
|
27
|
-
(words[0] + words[1..].join).to_sym
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/oas_rails/operation.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Operation < OasBase
|
3
|
-
attr_accessor :tags, :summary, :description, :operation_id, :parameters, :method, :docstring, :request_body, :responses, :security
|
4
|
-
|
5
|
-
def initialize(method:, summary:, operation_id:, **kwargs)
|
6
|
-
super()
|
7
|
-
@method = method
|
8
|
-
@summary = summary
|
9
|
-
@operation_id = operation_id
|
10
|
-
@tags = kwargs[:tags] || []
|
11
|
-
@description = kwargs[:description] || @summary
|
12
|
-
@parameters = kwargs[:parameters] || []
|
13
|
-
@request_body = kwargs[:request_body] || {}
|
14
|
-
@responses = kwargs[:responses] || {}
|
15
|
-
@security = kwargs[:security] || []
|
16
|
-
end
|
17
|
-
|
18
|
-
class << self
|
19
|
-
def from_oas_route(oas_route:)
|
20
|
-
summary = extract_summary(oas_route:)
|
21
|
-
operation_id = extract_operation_id(oas_route:)
|
22
|
-
tags = extract_tags(oas_route:)
|
23
|
-
description = oas_route.docstring
|
24
|
-
parameters = extract_parameters(oas_route:)
|
25
|
-
request_body = extract_request_body(oas_route:)
|
26
|
-
responses = extract_responses(oas_route:)
|
27
|
-
security = extract_security(oas_route:)
|
28
|
-
new(method: oas_route.verb.downcase, summary:, operation_id:, tags:, description:, parameters:, request_body:, responses:, security:)
|
29
|
-
end
|
30
|
-
|
31
|
-
def extract_summary(oas_route:)
|
32
|
-
oas_route.docstring.tags(:summary).first.try(:text) || generate_crud_name(oas_route.method, oas_route.controller.downcase) || oas_route.verb + " " + oas_route.path
|
33
|
-
end
|
34
|
-
|
35
|
-
def generate_crud_name(method, controller)
|
36
|
-
controller_name = controller.to_s.underscore.humanize.downcase.pluralize
|
37
|
-
|
38
|
-
case method.to_sym
|
39
|
-
when :index
|
40
|
-
"List #{controller_name}"
|
41
|
-
when :show
|
42
|
-
"View #{controller_name.singularize}"
|
43
|
-
when :create
|
44
|
-
"Create new #{controller_name.singularize}"
|
45
|
-
when :update
|
46
|
-
"Update #{controller_name.singularize}"
|
47
|
-
when :destroy
|
48
|
-
"Delete #{controller_name.singularize}"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def extract_operation_id(oas_route:)
|
53
|
-
"#{oas_route.method}#{oas_route.path.gsub('/', '_').gsub(/[{}]/, '')}"
|
54
|
-
end
|
55
|
-
|
56
|
-
# This method should check tags defined by yard, then extract tag from path namespace or controller name depending on configuration
|
57
|
-
def extract_tags(oas_route:)
|
58
|
-
tags = oas_route.docstring.tags(:tags).first
|
59
|
-
if !tags.nil?
|
60
|
-
tags.text.split(",").map(&:strip).map(&:titleize)
|
61
|
-
else
|
62
|
-
default_tags(oas_route:)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def default_tags(oas_route:)
|
67
|
-
tags = []
|
68
|
-
if OasRails.config.default_tags_from == "namespace"
|
69
|
-
tag = oas_route.path.split('/').reject(&:empty?).first.try(:titleize)
|
70
|
-
tags << tag unless tag.nil?
|
71
|
-
else
|
72
|
-
tags << oas_route.controller.titleize
|
73
|
-
end
|
74
|
-
tags
|
75
|
-
end
|
76
|
-
|
77
|
-
def extract_parameters(oas_route:)
|
78
|
-
parameters = []
|
79
|
-
parameters.concat(parameters_from_tags(tags: oas_route.docstring.tags(:parameter)))
|
80
|
-
oas_route.path_params.try(:map) do |p|
|
81
|
-
parameters << Parameter.from_path(path: oas_route.path, param: p) unless parameters.any? { |param| param.name.to_s == p.to_s }
|
82
|
-
end
|
83
|
-
parameters
|
84
|
-
end
|
85
|
-
|
86
|
-
def parameters_from_tags(tags:)
|
87
|
-
tags.map do |t|
|
88
|
-
Parameter.new(name: t.name, location: t.location, required: t.required, schema: t.schema, description: t.text)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def extract_request_body(oas_route:)
|
93
|
-
tag_request_body = oas_route.docstring.tags(:request_body).first
|
94
|
-
if tag_request_body.nil? && OasRails.config.autodiscover_request_body
|
95
|
-
oas_route.detect_request_body if %w[create update].include? oas_route.method
|
96
|
-
elsif !tag_request_body.nil?
|
97
|
-
RequestBody.from_tags(tag: tag_request_body, examples_tags: oas_route.docstring.tags(:request_body_example))
|
98
|
-
else
|
99
|
-
{}
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def extract_responses(oas_route:)
|
104
|
-
responses = Responses.from_tags(tags: oas_route.docstring.tags(:response))
|
105
|
-
|
106
|
-
if OasRails.config.autodiscover_responses
|
107
|
-
new_responses = oas_route.extract_responses_from_source
|
108
|
-
|
109
|
-
new_responses.each do |new_response|
|
110
|
-
responses.responses << new_response unless responses.responses.any? { |r| r.code == new_response.code }
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
responses
|
115
|
-
end
|
116
|
-
|
117
|
-
def extract_security(oas_route:)
|
118
|
-
return [] if oas_route.docstring.tags(:no_auth).any?
|
119
|
-
|
120
|
-
if (methods = oas_route.docstring.tags(:auth).first)
|
121
|
-
OasRails.config.security_schemas.keys.map { |key| { key => [] } }.select do |schema|
|
122
|
-
methods.types.include?(schema.keys.first.to_s)
|
123
|
-
end
|
124
|
-
elsif OasRails.config.authenticate_all_routes_by_default
|
125
|
-
OasRails.config.security_schemas.keys.map { |key| { key => [] } }
|
126
|
-
else
|
127
|
-
[]
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
def external_docs; end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
data/lib/oas_rails/parameter.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Parameter
|
3
|
-
STYLE_DEFAULTS = { query: 'form', path: 'simple', header: 'simple', cookie: 'form' }.freeze
|
4
|
-
|
5
|
-
attr_accessor :name, :in, :style, :description, :required, :schema
|
6
|
-
|
7
|
-
def initialize(name:, location:, description:, **kwargs)
|
8
|
-
@name = name
|
9
|
-
@in = location
|
10
|
-
@description = description
|
11
|
-
|
12
|
-
@required = kwargs[:required] || required?
|
13
|
-
@style = kwargs[:style] || default_from_in
|
14
|
-
@schema = kwargs[:schema] || { "type": 'string' }
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.from_path(path:, param:)
|
18
|
-
new(name: param, location: 'path',
|
19
|
-
description: "#{param.split('_')[-1].titleize} of existing #{extract_word_before(path, param).singularize}.")
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.extract_word_before(string, param)
|
23
|
-
regex = %r{/(\w+)/\{#{param}\}}
|
24
|
-
match = string.match(regex)
|
25
|
-
match ? match[1] : nil
|
26
|
-
end
|
27
|
-
|
28
|
-
def default_from_in
|
29
|
-
STYLE_DEFAULTS[@in.to_sym]
|
30
|
-
end
|
31
|
-
|
32
|
-
def required?
|
33
|
-
@in == 'path'
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_spec
|
37
|
-
{
|
38
|
-
"name": @name,
|
39
|
-
"in": @in,
|
40
|
-
"description": @description,
|
41
|
-
"required": @required,
|
42
|
-
"schema": @schema,
|
43
|
-
"style": @style
|
44
|
-
}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
data/lib/oas_rails/path_item.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class PathItem
|
3
|
-
attr_reader :path, :operations, :parameters
|
4
|
-
|
5
|
-
def initialize(path:, operations:, parameters:)
|
6
|
-
@path = path
|
7
|
-
@operations = operations
|
8
|
-
@parameters = parameters
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.from_oas_routes(path:, oas_routes:)
|
12
|
-
new(path: path, operations: oas_routes.map do |oas_route|
|
13
|
-
Operation.from_oas_route(oas_route: oas_route)
|
14
|
-
end, parameters: [])
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_spec
|
18
|
-
spec = {}
|
19
|
-
@operations.each do |o|
|
20
|
-
spec[o.method] = o.to_spec
|
21
|
-
end
|
22
|
-
spec
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/oas_rails/paths.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Paths
|
3
|
-
attr_accessor :path_items
|
4
|
-
|
5
|
-
def initialize(path_items:)
|
6
|
-
@path_items = path_items
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.from_string_paths(string_paths:)
|
10
|
-
new(path_items: string_paths.map do |s|
|
11
|
-
PathItem.from_oas_routes(path: s, oas_routes: RouteExtractor.host_routes_by_path(s))
|
12
|
-
end)
|
13
|
-
end
|
14
|
-
|
15
|
-
def to_spec
|
16
|
-
@path_items.each_with_object({}) { |p, object| object[p.path] = p.to_spec }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class RequestBody < OasBase
|
3
|
-
attr_accessor :description, :content, :required
|
4
|
-
|
5
|
-
def initialize(description:, content:, required: false)
|
6
|
-
super()
|
7
|
-
@description = description
|
8
|
-
@content = content # Should be an array of media type object
|
9
|
-
@required = required
|
10
|
-
end
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def from_tags(tag:, examples_tags: [])
|
14
|
-
if tag.klass.ancestors.include? ActiveRecord::Base
|
15
|
-
from_model_class(klass: tag.klass, description: tag.text, required: tag.required, examples_tags:)
|
16
|
-
else
|
17
|
-
# hash content to schema
|
18
|
-
content = { "application/json": MediaType.new(schema: tag.schema, examples: MediaType.tags_to_examples(tags: examples_tags)) }
|
19
|
-
new(description: tag.text, content:, required: tag.required)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def from_model_class(klass:, **kwargs)
|
24
|
-
content = { "application/json": MediaType.from_model_class(klass:, examples: MediaType.tags_to_examples(tags: kwargs[:examples_tags] || {})) }
|
25
|
-
new(description: kwargs[:description] || klass.to_s, content:, required: kwargs[:required])
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
data/lib/oas_rails/response.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Response < OasBase
|
3
|
-
attr_accessor :code, :description, :content
|
4
|
-
|
5
|
-
def initialize(code:, description:, content:)
|
6
|
-
super()
|
7
|
-
@code = code
|
8
|
-
@description = description
|
9
|
-
@content = content # Should be an array of media type object
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
data/lib/oas_rails/responses.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Responses < OasBase
|
3
|
-
attr_accessor :responses
|
4
|
-
|
5
|
-
def initialize(responses)
|
6
|
-
super()
|
7
|
-
@responses = responses
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_spec
|
11
|
-
@responses.each_with_object({}) { |r, object| object[r.code] = r.to_spec }
|
12
|
-
end
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def from_tags(tags:)
|
16
|
-
new(tags.map { |t| Response.new(code: t.name.to_i, description: t.text, content: { "application/json": MediaType.new(schema: t.schema) }) })
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,119 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class RouteExtractor
|
3
|
-
RAILS_DEFAULT_CONTROLLERS = %w[
|
4
|
-
rails/info
|
5
|
-
rails/mailers
|
6
|
-
active_storage/blobs
|
7
|
-
active_storage/disk
|
8
|
-
active_storage/direct_uploads
|
9
|
-
active_storage/representations
|
10
|
-
rails/conductor/continuous_integration
|
11
|
-
rails/conductor/multiple_databases
|
12
|
-
rails/conductor/action_mailbox
|
13
|
-
rails/conductor/action_text
|
14
|
-
action_cable
|
15
|
-
].freeze
|
16
|
-
|
17
|
-
RAILS_DEFAULT_PATHS = %w[
|
18
|
-
/rails/action_mailbox/
|
19
|
-
].freeze
|
20
|
-
|
21
|
-
class << self
|
22
|
-
def host_routes_by_path(path)
|
23
|
-
@host_routes ||= extract_host_routes
|
24
|
-
@host_routes.select { |r| r.path == path }
|
25
|
-
end
|
26
|
-
|
27
|
-
def host_routes
|
28
|
-
@host_routes ||= extract_host_routes
|
29
|
-
end
|
30
|
-
|
31
|
-
# Clear Class Instance Variable @host_routes
|
32
|
-
#
|
33
|
-
# This method clear the class instance variable @host_routes
|
34
|
-
# to force a extraction of the routes again.
|
35
|
-
def clear_cache
|
36
|
-
@host_routes = nil
|
37
|
-
end
|
38
|
-
|
39
|
-
def host_paths
|
40
|
-
@host_paths ||= host_routes.map(&:path).uniq.sort
|
41
|
-
end
|
42
|
-
|
43
|
-
def clean_route(route)
|
44
|
-
route.gsub('(.:format)', '').gsub(/:\w+/) { |match| "{#{match[1..]}}" }
|
45
|
-
end
|
46
|
-
|
47
|
-
# THIS CODE IS NOT IN USE BUT CAN BE USEFULL WITH GLOBAL TAGS OR AUTH TAGS
|
48
|
-
# def get_controller_comments(controller_path)
|
49
|
-
# YARD.parse_string(File.read(controller_path))
|
50
|
-
# controller_class = YARD::Registry.all(:class).first
|
51
|
-
# if controller_class
|
52
|
-
# class_comment = controller_class.docstring.all
|
53
|
-
# method_comments = controller_class.meths.map do |method|
|
54
|
-
# {
|
55
|
-
# name: method.name,
|
56
|
-
# comment: method.docstring.all
|
57
|
-
# }
|
58
|
-
# end
|
59
|
-
# YARD::Registry.clear
|
60
|
-
# {
|
61
|
-
# class_comment: class_comment,
|
62
|
-
# method_comments: method_comments
|
63
|
-
# }
|
64
|
-
# else
|
65
|
-
# YARD::Registry.clear
|
66
|
-
# nil
|
67
|
-
# end
|
68
|
-
# rescue StandardError
|
69
|
-
# nil
|
70
|
-
# end
|
71
|
-
#
|
72
|
-
# def get_controller_comment(controller_path)
|
73
|
-
# get_controller_comments(controller_path)&.dig(:class_comment) || ''
|
74
|
-
# rescue StandardError
|
75
|
-
# ''
|
76
|
-
# end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def extract_host_routes
|
81
|
-
Rails.application.routes.routes.select do |route|
|
82
|
-
valid_api_route?(route)
|
83
|
-
end.map { |r| OasRoute.new_from_rails_route(rails_route: r) }
|
84
|
-
end
|
85
|
-
|
86
|
-
def valid_api_route?(route)
|
87
|
-
return false unless valid_route_implementation?(route)
|
88
|
-
return false if RAILS_DEFAULT_CONTROLLERS.any? { |default| route.defaults[:controller].start_with?(default) }
|
89
|
-
return false if RAILS_DEFAULT_PATHS.any? { |path| route.path.spec.to_s.include?(path) }
|
90
|
-
return false unless route.path.spec.to_s.start_with?(OasRails.config.api_path)
|
91
|
-
|
92
|
-
true
|
93
|
-
end
|
94
|
-
|
95
|
-
# Checks if a route has a valid implementation.
|
96
|
-
#
|
97
|
-
# This method verifies that both the controller and the action specified
|
98
|
-
# in the route exist. It checks if the controller class is defined and
|
99
|
-
# if the action method is implemented within that controller.
|
100
|
-
#
|
101
|
-
# @param route [ActionDispatch::Journey::Route] The route to check.
|
102
|
-
# @return [Boolean] true if both the controller and action exist, false otherwise.
|
103
|
-
def valid_route_implementation?(route)
|
104
|
-
controller_name = route.defaults[:controller]&.camelize
|
105
|
-
action_name = route.defaults[:action]
|
106
|
-
|
107
|
-
return false if controller_name.blank? || action_name.blank?
|
108
|
-
|
109
|
-
controller_class = "#{controller_name}Controller".safe_constantize
|
110
|
-
|
111
|
-
if controller_class.nil?
|
112
|
-
false
|
113
|
-
else
|
114
|
-
controller_class.instance_methods.include?(action_name.to_sym)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
data/lib/oas_rails/server.rb
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module OasRails
|
4
|
-
class Specification
|
5
|
-
# Initializes a new Specification object.
|
6
|
-
# Clears the cache if running in the development environment.
|
7
|
-
def initialize
|
8
|
-
clear_cache unless Rails.env.production?
|
9
|
-
|
10
|
-
@specification = base_spec
|
11
|
-
end
|
12
|
-
|
13
|
-
# Clears the cache for MethodSource and RouteExtractor.
|
14
|
-
#
|
15
|
-
# @return [void]
|
16
|
-
def clear_cache
|
17
|
-
MethodSource.clear_cache
|
18
|
-
RouteExtractor.clear_cache
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_json(*_args)
|
22
|
-
@specification.to_json
|
23
|
-
rescue StandardError => e
|
24
|
-
Rails.logger.error("Error Generating OAS: #{e.message}")
|
25
|
-
{}
|
26
|
-
end
|
27
|
-
|
28
|
-
# Create the Base of the OAS hash.
|
29
|
-
# @see https://spec.openapis.org/oas/latest.html#schema
|
30
|
-
def base_spec
|
31
|
-
{
|
32
|
-
openapi: '3.1.0',
|
33
|
-
info: OasRails.config.info.to_spec,
|
34
|
-
servers: OasRails.config.servers.map(&:to_spec),
|
35
|
-
paths:,
|
36
|
-
components:,
|
37
|
-
security:,
|
38
|
-
tags: OasRails.config.tags.map(&:to_spec),
|
39
|
-
externalDocs: {}
|
40
|
-
}
|
41
|
-
end
|
42
|
-
|
43
|
-
# Create the Security Requirement Object.
|
44
|
-
# @see https://spec.openapis.org/oas/latest.html#security-requirement-object
|
45
|
-
def security
|
46
|
-
return [] unless OasRails.config.authenticate_all_routes_by_default
|
47
|
-
|
48
|
-
OasRails.config.security_schemas.map { |key, _| { key => [] } }
|
49
|
-
end
|
50
|
-
|
51
|
-
# Create the Paths Object For the Root of the OAS.
|
52
|
-
# @see https://spec.openapis.org/oas/latest.html#paths-object
|
53
|
-
def paths
|
54
|
-
Paths.from_string_paths(string_paths: RouteExtractor.host_paths).to_spec
|
55
|
-
end
|
56
|
-
|
57
|
-
# Created the Components Object For the Root of the OAS.
|
58
|
-
# @see https://spec.openapis.org/oas/latest.html#components-object
|
59
|
-
def components
|
60
|
-
{
|
61
|
-
schemas: {}, parameters: {}, securitySchemes: security_schemas, requestBodies: {}, responses: {},
|
62
|
-
headers: {}, examples: {}, links: {}, callbacks: {}
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
# Create the Security Schemas Array inside components field of the OAS.
|
67
|
-
# @see https://spec.openapis.org/oas/latest.html#security-scheme-object
|
68
|
-
def security_schemas
|
69
|
-
OasRails.config.security_schemas
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
data/lib/oas_rails/tag.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module OasRails
|
2
|
-
class Tag
|
3
|
-
attr_accessor :name, :description
|
4
|
-
|
5
|
-
def initialize(name:, description:)
|
6
|
-
@name = name.titleize
|
7
|
-
@description = description
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_spec
|
11
|
-
{
|
12
|
-
name: @name,
|
13
|
-
description: @description
|
14
|
-
}
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|