rails-autodoc 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +63 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.rubocop.yml +81 -0
- data/.yardopts +3 -0
- data/Appraisals +26 -0
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTING.md +54 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +298 -0
- data/LICENSE.txt +21 -0
- data/README.md +111 -0
- data/Rakefile +26 -0
- data/app/controllers/rails_autodoc/spec_controller.rb +52 -0
- data/config/routes.rb +6 -0
- data/docs/annotation-dsl.md +56 -0
- data/docs/architecture.md +37 -0
- data/docs/ci-integration.md +32 -0
- data/docs/configuration.md +48 -0
- data/docs/faq.md +29 -0
- data/docs/getting-started.md +54 -0
- data/docs/index.md +21 -0
- data/docs/inference-rules.md +74 -0
- data/docs/limitations.md +34 -0
- data/docs/migration-from-rswag.md +42 -0
- data/docs/serializer-support.md +25 -0
- data/lib/generators/rails_autodoc/install_generator.rb +34 -0
- data/lib/generators/rails_autodoc/templates/autodoc-verify.yml +19 -0
- data/lib/generators/rails_autodoc/templates/initializer.rb +20 -0
- data/lib/rails_autodoc/ast_traversal.rb +74 -0
- data/lib/rails_autodoc/configuration.rb +45 -0
- data/lib/rails_autodoc/dsl/controller_extensions.rb +65 -0
- data/lib/rails_autodoc/engine.rb +13 -0
- data/lib/rails_autodoc/generator.rb +54 -0
- data/lib/rails_autodoc/openapi_spec_builder.rb +334 -0
- data/lib/rails_autodoc/railtie.rb +25 -0
- data/lib/rails_autodoc/registry.rb +71 -0
- data/lib/rails_autodoc/response_inferencer.rb +158 -0
- data/lib/rails_autodoc/route_inspector.rb +139 -0
- data/lib/rails_autodoc/schema_mapper.rb +142 -0
- data/lib/rails_autodoc/serializers/active_model_serializer.rb +27 -0
- data/lib/rails_autodoc/serializers/alba.rb +39 -0
- data/lib/rails_autodoc/serializers/base.rb +19 -0
- data/lib/rails_autodoc/serializers/blueprinter.rb +27 -0
- data/lib/rails_autodoc/serializers/registry.rb +29 -0
- data/lib/rails_autodoc/strong_params_parser.rb +188 -0
- data/lib/rails_autodoc/tasks/autodoc.rake +26 -0
- data/lib/rails_autodoc/version.rb +5 -0
- data/lib/rails_autodoc.rb +47 -0
- data/mkdocs.yml +16 -0
- data/rails-autodoc.gemspec +61 -0
- data/spec/combustion/config.ru +4 -0
- data/spec/dummy/app/assets/config/manifest.js +1 -0
- data/spec/dummy/app/controllers/api/v1/users_controller.rb +45 -0
- data/spec/dummy/app/models/user.rb +5 -0
- data/spec/dummy/config/application.rb +14 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +3 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/test.rb +12 -0
- data/spec/dummy/config/initializers/rails_autodoc.rb +8 -0
- data/spec/dummy/config/initializers/sqlite3_boolean.rb +8 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/db/migrate/001_create_users.rb +14 -0
- data/spec/dummy/db/schema.rb +12 -0
- data/spec/rails_autodoc/configuration_spec.rb +34 -0
- data/spec/rails_autodoc/dsl_integration_spec.rb +77 -0
- data/spec/rails_autodoc/engine_spec.rb +26 -0
- data/spec/rails_autodoc/gem_spec.rb +27 -0
- data/spec/rails_autodoc/generator_spec.rb +39 -0
- data/spec/rails_autodoc/golden_spec.rb +67 -0
- data/spec/rails_autodoc/integration_spec.rb +114 -0
- data/spec/rails_autodoc/registry_spec.rb +26 -0
- data/spec/rails_autodoc/response_inferencer_spec.rb +26 -0
- data/spec/rails_autodoc/route_inspector_spec.rb +56 -0
- data/spec/rails_autodoc/schema_mapper_spec.rb +42 -0
- data/spec/rails_autodoc/serializers/registry_spec.rb +33 -0
- data/spec/rails_autodoc/strong_params_parser_spec.rb +41 -0
- data/spec/spec_helper.rb +43 -0
- metadata +320 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "RailsAutodoc gem packaging" do
|
|
6
|
+
it "builds a non-empty gemspec file list" do
|
|
7
|
+
gemspec = Gem::Specification.load("rails-autodoc.gemspec")
|
|
8
|
+
|
|
9
|
+
expect(gemspec.files).not_to be_empty
|
|
10
|
+
expect(gemspec.files).to include("lib/rails_autodoc.rb")
|
|
11
|
+
expect(gemspec.files).to include("lib/rails_autodoc/generator.rb")
|
|
12
|
+
expect(gemspec.files).to include("README.md")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "requires Ruby 2.7 or newer" do
|
|
16
|
+
gemspec = Gem::Specification.load("rails-autodoc.gemspec")
|
|
17
|
+
|
|
18
|
+
expect(gemspec.required_ruby_version).to eq(Gem::Requirement.new(">= 2.7.0"))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "declares runtime dependencies needed for inference" do
|
|
22
|
+
gemspec = Gem::Specification.load("rails-autodoc.gemspec")
|
|
23
|
+
names = gemspec.dependencies.map(&:name)
|
|
24
|
+
|
|
25
|
+
expect(names).to include("activesupport", "parser", "psych", "railties")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::Generator do
|
|
6
|
+
subject(:generator) { described_class.new }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
Rails.application.routes.draw do
|
|
10
|
+
mount RailsAutodoc::Engine => "/api-docs"
|
|
11
|
+
namespace :api do
|
|
12
|
+
namespace :v1 do
|
|
13
|
+
resources :users, only: %i[index show create update destroy]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "generates a valid OpenAPI document" do
|
|
20
|
+
spec = generator.generate
|
|
21
|
+
expect(spec["openapi"]).to eq("3.0.3")
|
|
22
|
+
expect(spec["paths"]).not_to be_empty
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "includes user paths" do
|
|
26
|
+
spec = generator.generate
|
|
27
|
+
expect(spec["paths"].keys).to include("/api/v1/users", "/api/v1/users/{id}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "writes spec to configured output path" do
|
|
31
|
+
generator.generate!
|
|
32
|
+
expect(RailsAutodoc.config.resolved_output_path).to exist
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "verifies unchanged specs" do
|
|
36
|
+
generator.generate!
|
|
37
|
+
expect { generator.verify! }.not_to raise_error
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Golden OpenAPI fixtures" do
|
|
6
|
+
before do
|
|
7
|
+
users_controller = Class.new(ActionController::API) do
|
|
8
|
+
def self.name
|
|
9
|
+
"Api::V1::UsersController"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def index
|
|
13
|
+
render json: User.all
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create
|
|
17
|
+
user = User.new(user_params)
|
|
18
|
+
render json: user, status: :created
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def user_params
|
|
24
|
+
params.require(:user).permit(:name, :email, :age, address: %i[street city], tags: [])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
stub_const("Api::V1::UsersController", users_controller)
|
|
29
|
+
|
|
30
|
+
Rails.application.routes.draw do
|
|
31
|
+
namespace :api do
|
|
32
|
+
namespace :v1 do
|
|
33
|
+
resources :users, only: %i[index create]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "matches expected create request schema fields" do
|
|
40
|
+
spec = RailsAutodoc::Generator.new.generate
|
|
41
|
+
post_operation = spec.dig("paths", "/api/v1/users", "post")
|
|
42
|
+
user_schema = post_operation.dig("requestBody", "content", "application/json", "schema", "properties", "user",
|
|
43
|
+
"properties")
|
|
44
|
+
|
|
45
|
+
expect(user_schema.keys).to include("name", "email", "age", "address", "tags")
|
|
46
|
+
expect(user_schema["age"]["type"]).to eq("integer")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "matches key sections from the golden fixture" do
|
|
50
|
+
expected = YAML.safe_load(
|
|
51
|
+
File.read(File.expand_path("../fixtures/expected_specs/users_index_create.yaml", __dir__)),
|
|
52
|
+
permitted_classes: [Date, Time]
|
|
53
|
+
)
|
|
54
|
+
actual = RailsAutodoc::Generator.new.generate
|
|
55
|
+
|
|
56
|
+
expect(actual.dig("paths", "/api/v1/users", "get", "responses", "200")).to be_present
|
|
57
|
+
expect(actual.dig("paths", "/api/v1/users", "post", "requestBody", "required")).to be(true)
|
|
58
|
+
expect(actual.dig("paths", "/api/v1/users", "post", "responses", "201")).to be_present
|
|
59
|
+
|
|
60
|
+
expected_post_schema = expected.dig("paths", "/api/v1/users", "post", "requestBody", "content", "application/json",
|
|
61
|
+
"schema")
|
|
62
|
+
actual_post_schema = actual.dig("paths", "/api/v1/users", "post", "requestBody", "content", "application/json",
|
|
63
|
+
"schema")
|
|
64
|
+
|
|
65
|
+
expect(actual_post_schema).to eq(expected_post_schema)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "RailsAutodoc integration", type: :request do
|
|
6
|
+
let(:generator) { RailsAutodoc::Generator.new }
|
|
7
|
+
let(:spec) { generator.generate }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
RailsAutodoc.configure do |config|
|
|
11
|
+
config.title = "Dummy API"
|
|
12
|
+
config.version = "1.0.0"
|
|
13
|
+
config.output_path = Rails.root.join("tmp/openapi.yaml")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
Rails.application.routes.draw do
|
|
17
|
+
mount RailsAutodoc::Engine => "/api-docs"
|
|
18
|
+
namespace :api do
|
|
19
|
+
namespace :v1 do
|
|
20
|
+
resources :users, only: %i[index show create update destroy]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "loads the published gem version" do
|
|
27
|
+
expect(RailsAutodoc::VERSION).to match(/\A\d+\.\d+\.\d+\z/)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "generates a complete OpenAPI document" do
|
|
31
|
+
expect(spec).to include("openapi", "info", "servers", "tags", "paths", "components")
|
|
32
|
+
expect(spec["openapi"]).to eq("3.0.3")
|
|
33
|
+
expect(spec.dig("info", "title")).to eq("Dummy API")
|
|
34
|
+
expect(spec.dig("info", "version")).to eq("1.0.0")
|
|
35
|
+
expect(spec["servers"]).not_to be_empty
|
|
36
|
+
expect(spec["tags"]).not_to be_empty
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "documents CRUD user paths" do
|
|
40
|
+
expect(spec["paths"].keys).to include("/api/v1/users", "/api/v1/users/{id}")
|
|
41
|
+
expect(spec.dig("paths", "/api/v1/users", "get", "operationId")).to eq("api_v1_users_controller_index")
|
|
42
|
+
expect(spec.dig("paths", "/api/v1/users", "post", "operationId")).to eq("api_v1_users_controller_create")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "documents path parameters for member routes" do
|
|
46
|
+
parameters = spec.dig("paths", "/api/v1/users/{id}", "get", "parameters")
|
|
47
|
+
id_param = parameters.find { |entry| entry["name"] == "id" }
|
|
48
|
+
|
|
49
|
+
expect(id_param).to include("in" => "path", "required" => true)
|
|
50
|
+
expect(id_param.dig("schema", "type")).to eq("string")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "documents nested strong params on create" do
|
|
54
|
+
user_schema = spec.dig(
|
|
55
|
+
"paths", "/api/v1/users", "post",
|
|
56
|
+
"requestBody", "content", "application/json", "schema",
|
|
57
|
+
"properties", "user", "properties"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
expect(user_schema.keys).to include("name", "email", "age", "address", "tags")
|
|
61
|
+
expect(user_schema["age"]["type"]).to eq("integer")
|
|
62
|
+
expect(user_schema["address"]["type"]).to eq("object")
|
|
63
|
+
expect(user_schema["tags"]["type"]).to eq("array")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "infers response status codes from controller actions" do
|
|
67
|
+
expect(spec.dig("paths", "/api/v1/users", "post", "responses").keys).to include("201", "422")
|
|
68
|
+
expect(spec.dig("paths", "/api/v1/users/{id}", "delete", "responses").keys).to include("204")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "includes User schema in components" do
|
|
72
|
+
user_component = spec.dig("components", "schemas", "User")
|
|
73
|
+
|
|
74
|
+
expect(user_component).to include("type" => "object")
|
|
75
|
+
expect(user_component).to have_key("properties")
|
|
76
|
+
expect(user_component["properties"].keys).to include("name", "email", "age", "active")
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "does not document excluded mount paths" do
|
|
80
|
+
expect(spec["paths"].keys).not_to include("/api-docs")
|
|
81
|
+
expect(spec["paths"].keys).not_to include("/api-docs/spec.json")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "raises when generated output drifts from committed file" do
|
|
85
|
+
output_path = RailsAutodoc.config.resolved_output_path
|
|
86
|
+
original = output_path.exist? ? output_path.read : nil
|
|
87
|
+
generator.generate!
|
|
88
|
+
|
|
89
|
+
expect { generator.verify! }.not_to raise_error
|
|
90
|
+
|
|
91
|
+
output_path.write("openapi: 3.0.3\ninfo:\n title: Changed\n")
|
|
92
|
+
|
|
93
|
+
expect { generator.verify! }.to raise_error(
|
|
94
|
+
RailsAutodoc::SpecDriftError,
|
|
95
|
+
/OpenAPI spec drift detected/
|
|
96
|
+
)
|
|
97
|
+
ensure
|
|
98
|
+
if original
|
|
99
|
+
output_path.write(original)
|
|
100
|
+
elsif output_path.exist?
|
|
101
|
+
output_path.delete
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "serves generated operations over HTTP" do
|
|
106
|
+
get "/api-docs/spec.json"
|
|
107
|
+
|
|
108
|
+
expect(response).to have_http_status(:ok)
|
|
109
|
+
|
|
110
|
+
body = JSON.parse(response.body)
|
|
111
|
+
expect(body.dig("paths", "/api/v1/users", "post", "requestBody")).not_to be_nil
|
|
112
|
+
expect(body.dig("components", "schemas", "User", "properties", "email", "type")).to eq("string")
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::Registry do
|
|
6
|
+
controller_class = Class.new do
|
|
7
|
+
def self.name
|
|
8
|
+
"DocsController"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "registers annotation overrides" do
|
|
13
|
+
RailsAutodoc.registry.register(controller_class, :create) do
|
|
14
|
+
summary "Create resource"
|
|
15
|
+
tag "Docs"
|
|
16
|
+
body_param :role, :string, enum: %w[admin user]
|
|
17
|
+
response 201, ref: "User"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
annotation = RailsAutodoc.registry.find(controller_class, :create)
|
|
21
|
+
expect(annotation.summary).to eq("Create resource")
|
|
22
|
+
expect(annotation.tags).to include("Docs")
|
|
23
|
+
expect(annotation.body_params.first[:enum]).to eq(%w[admin user])
|
|
24
|
+
expect(annotation.responses["201"][:ref]).to eq("User")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::ResponseInferencer do
|
|
6
|
+
let(:source_path) { File.expand_path("../dummy/app/controllers/api/v1/users_controller.rb", __dir__) }
|
|
7
|
+
|
|
8
|
+
subject(:inferencer) do
|
|
9
|
+
described_class.new(source_path: source_path, class_name: "Api::V1::UsersController")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "infers default GET response" do
|
|
13
|
+
responses = inferencer.responses_for_action("index", verb: "GET")
|
|
14
|
+
expect(responses.first.status).to eq("200")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "infers POST created status from render call" do
|
|
18
|
+
responses = inferencer.responses_for_action("create", verb: "POST")
|
|
19
|
+
expect(responses.map(&:status)).to include("201")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "infers DELETE no content" do
|
|
23
|
+
responses = inferencer.responses_for_action("destroy", verb: "DELETE")
|
|
24
|
+
expect(responses.map(&:status)).to include("204")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::RouteInspector do
|
|
6
|
+
subject(:operations) { described_class.new.operations }
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
users_controller = Class.new(ActionController::API) do
|
|
10
|
+
def self.name
|
|
11
|
+
"Api::V1::UsersController"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def index
|
|
15
|
+
head :ok
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def show
|
|
19
|
+
head :ok
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create
|
|
23
|
+
head :ok
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
stub_const("Api::V1::UsersController", users_controller)
|
|
28
|
+
|
|
29
|
+
Rails.application.routes.draw do
|
|
30
|
+
namespace :api do
|
|
31
|
+
namespace :v1 do
|
|
32
|
+
resources :users, only: %i[index show create]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "discovers REST routes" do
|
|
39
|
+
expect(operations.map(&:verb)).to include("GET", "POST")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "extracts path parameters" do
|
|
43
|
+
show_operation = operations.find { |op| op.action == "show" }
|
|
44
|
+
expect(show_operation.path_params).to include("id")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "normalizes OpenAPI path templates" do
|
|
48
|
+
show_operation = operations.find { |op| op.action == "show" }
|
|
49
|
+
expect(show_operation.openapi_path).to eq("/api/v1/users/{id}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "assigns controller tags" do
|
|
53
|
+
operation = operations.find { |op| op.action == "index" }
|
|
54
|
+
expect(operation.tags).to include("Users")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::SchemaMapper do
|
|
6
|
+
let(:schema_path) { Rails.root.join("db/schema.rb") }
|
|
7
|
+
|
|
8
|
+
subject(:mapper) { described_class.new(schema_path: schema_path) }
|
|
9
|
+
|
|
10
|
+
it "loads tables from schema.rb" do
|
|
11
|
+
expect(mapper.all_model_schemas).to have_key("User")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "maps string columns" do
|
|
15
|
+
schema = mapper.model_schema("User")
|
|
16
|
+
expect(schema[:properties]["name"][:type]).to eq("string")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "maps integer columns" do
|
|
20
|
+
schema = mapper.model_schema("User")
|
|
21
|
+
expect(schema[:properties]["age"][:type]).to eq("integer")
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "maps boolean columns" do
|
|
25
|
+
schema = mapper.model_schema("User")
|
|
26
|
+
expect(schema[:properties]["active"][:type]).to eq("boolean")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "applies model types to param schemas" do
|
|
30
|
+
param_schema = {
|
|
31
|
+
type: "object",
|
|
32
|
+
properties: {
|
|
33
|
+
"name" => { type: "string" },
|
|
34
|
+
"age" => { type: "string" }
|
|
35
|
+
},
|
|
36
|
+
required: []
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
mapper.apply_types!(param_schema, model_name: "User")
|
|
40
|
+
expect(param_schema[:properties]["age"][:type]).to eq("integer")
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::Serializers::Registry do
|
|
6
|
+
let(:registry) { described_class.new }
|
|
7
|
+
|
|
8
|
+
describe "Blueprinter adapter" do
|
|
9
|
+
let(:serializer_class) do
|
|
10
|
+
Class.new do
|
|
11
|
+
def self.name
|
|
12
|
+
"UserBlueprint"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.fields
|
|
16
|
+
{ id: {}, email: {}, name: {} }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
before do
|
|
22
|
+
stub_const("Blueprinter", Module.new)
|
|
23
|
+
stub_const("Blueprinter::Base", Class.new)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "builds schema from serializer fields" do
|
|
27
|
+
adapter = RailsAutodoc::Serializers::Blueprinter.new
|
|
28
|
+
allow(adapter).to receive(:detect?).and_return(true)
|
|
29
|
+
schema = adapter.schema_for(serializer_class)
|
|
30
|
+
expect(schema[:properties].keys).to include("id", "email", "name")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe RailsAutodoc::StrongParamsParser do
|
|
6
|
+
let(:source_path) { File.expand_path("../fixtures/controllers/sample_controller.rb", __dir__) }
|
|
7
|
+
|
|
8
|
+
subject(:parser) do
|
|
9
|
+
described_class.new(source_path: source_path, class_name: "SampleController")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "extracts param methods" do
|
|
13
|
+
methods = parser.param_methods
|
|
14
|
+
expect(methods).to have_key("sample_params")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "parses required root key" do
|
|
18
|
+
result = parser.param_methods["sample_params"]
|
|
19
|
+
expect(result.root_key).to eq(:sample)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "parses scalar permitted fields" do
|
|
23
|
+
properties = parser.param_methods["sample_params"].schema[:properties]
|
|
24
|
+
expect(properties).to include("name", "email")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "parses nested hash fields" do
|
|
28
|
+
properties = parser.param_methods["sample_params"].schema[:properties]
|
|
29
|
+
expect(properties["address"][:type]).to eq("object")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "parses array fields" do
|
|
33
|
+
properties = parser.param_methods["sample_params"].schema[:properties]
|
|
34
|
+
expect(properties["tags"][:type]).to eq("array")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "maps params to actions" do
|
|
38
|
+
result = parser.params_for_action("create")
|
|
39
|
+
expect(result.method_name).to eq("sample_params")
|
|
40
|
+
end
|
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails"
|
|
4
|
+
require "rails_autodoc"
|
|
5
|
+
require "combustion"
|
|
6
|
+
|
|
7
|
+
Combustion.path = "spec/dummy"
|
|
8
|
+
Combustion.initialize! :all
|
|
9
|
+
|
|
10
|
+
[Rails.root.join("app/models"), Rails.root.join("app/controllers")].each do |load_path|
|
|
11
|
+
Dir[load_path.join("**", "*.rb")].sort.each { |path| require path }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
require "rspec/rails"
|
|
15
|
+
|
|
16
|
+
RSpec.configure do |config|
|
|
17
|
+
config.expect_with :rspec do |expectations|
|
|
18
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
config.mock_with :rspec do |mocks|
|
|
22
|
+
mocks.verify_partial_doubles = true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
26
|
+
config.filter_run_when_matching :focus
|
|
27
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
|
28
|
+
config.disable_monkey_patching!
|
|
29
|
+
config.order = :random
|
|
30
|
+
Kernel.srand config.seed
|
|
31
|
+
|
|
32
|
+
config.before(:each) do
|
|
33
|
+
RailsAutodoc.registry.clear!
|
|
34
|
+
load Rails.root.join("config/initializers/rails_autodoc.rb")
|
|
35
|
+
clear_spec_controller_cache
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def clear_spec_controller_cache
|
|
40
|
+
return unless defined?(RailsAutodoc::SpecController)
|
|
41
|
+
|
|
42
|
+
RailsAutodoc::SpecController.cached_spec = nil
|
|
43
|
+
end
|