oas_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +147 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/oas_rails_manifest.js +1 -0
  6. data/app/assets/stylesheets/oas_rails/application.css +15 -0
  7. data/app/controllers/oas_rails/application_controller.rb +4 -0
  8. data/app/controllers/oas_rails/oas_rails_controller.rb +9 -0
  9. data/app/helpers/oas_rails/application_helper.rb +4 -0
  10. data/app/helpers/oas_rails/oas_rails_helper.rb +4 -0
  11. data/app/helpers/oas_rails/test_helper.rb +4 -0
  12. data/app/jobs/oas_rails/application_job.rb +4 -0
  13. data/app/mailers/oas_rails/application_mailer.rb +6 -0
  14. data/app/models/oas_rails/application_record.rb +5 -0
  15. data/app/views/layouts/oas_rails/application.html.erb +18 -0
  16. data/app/views/oas_rails/oas_rails/index.html.erb +1 -0
  17. data/app/views/oas_rails/test/show.html.erb +1 -0
  18. data/config/routes.rb +4 -0
  19. data/lib/generators/oas_rails/config/config_generator.rb +11 -0
  20. data/lib/generators/oas_rails/config/templates/oas_rails_initializer.rb +49 -0
  21. data/lib/oas_rails/configuration.rb +28 -0
  22. data/lib/oas_rails/contact.rb +12 -0
  23. data/lib/oas_rails/engine.rb +5 -0
  24. data/lib/oas_rails/info.rb +60 -0
  25. data/lib/oas_rails/license.rb +11 -0
  26. data/lib/oas_rails/media_type.rb +57 -0
  27. data/lib/oas_rails/oas_base.rb +29 -0
  28. data/lib/oas_rails/oas_route.rb +143 -0
  29. data/lib/oas_rails/operation.rb +118 -0
  30. data/lib/oas_rails/parameter.rb +47 -0
  31. data/lib/oas_rails/path_item.rb +25 -0
  32. data/lib/oas_rails/paths.rb +19 -0
  33. data/lib/oas_rails/request_body.rb +29 -0
  34. data/lib/oas_rails/response.rb +12 -0
  35. data/lib/oas_rails/responses.rb +20 -0
  36. data/lib/oas_rails/route_extractor.rb +87 -0
  37. data/lib/oas_rails/server.rb +10 -0
  38. data/lib/oas_rails/specification.rb +42 -0
  39. data/lib/oas_rails/tag.rb +17 -0
  40. data/lib/oas_rails/version.rb +3 -0
  41. data/lib/oas_rails/yard/oas_yard_factory.rb +160 -0
  42. data/lib/oas_rails.rb +120 -0
  43. metadata +159 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7eb785a5d2e4c2bf2ab00931fded8770c0f162b21dee065c9770f159f0ddd86d
4
+ data.tar.gz: 2ce8852c11a5f9d2e6263bc7f067e12e83029a9f87aeefc6912884f0c5912408
5
+ SHA512:
6
+ metadata.gz: 8a869a622b0cc9dc8710e665b70732d9993b16dce77ebae9529c73be10e794cb5a1820213dcca99380d05e810df04e00eb2ba6e11c5457c0ec76b9b82c7a740e
7
+ data.tar.gz: 515c5e3a66de74241ec303dfe276104d86bee128d0cc790d40a3dcff8534dcb3dbf7d283201bffd0b4089d30b03fc90f567d512714663f6dd0d39535bae0ae92
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright a-chacon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Open API Specification For Rails
2
+
3
+ OasRails is a Rails engine for generating **automatic interactive documentation for your Rails APIs**. It generates an **OAS 3.1** document and displays it using **[RapiDoc](https://rapidocweb.com)**.
4
+
5
+ ## Related Projects
6
+
7
+ - **[ApiPie](https://github.com/Apipie/apipie-rails)**: Doesn't support OAS 3.1, requires learning a DSL, lacks a nice UI
8
+ - **[swagger_yard-rails](https://github.com/livingsocial/swagger_yard-rails)**: Seems abandoned, but serves as inspiration
9
+ - **[Rswag](https://github.com/rswag/rswag)**: Not automatic, depends on RSpec; Many developers now use Minitest as it's the default test framework
10
+ - **[grape-swagger](https://github.com/ruby-grape/grape-swagger)**: Requires Grape
11
+ - **[rspec_api_documentation](https://github.com/zipmark/rspec_api_documentation)**: Requires RSpec and a command to generate the docs
12
+
13
+ ## What Sets OasRails Apart?
14
+
15
+ - **Dynamic**: No command required to generate docs
16
+ - **Simple**: Complement default documentation with a few comments; no need to learn a complex DSL
17
+ - **Pure Ruby on Rails APIs**: No additional frameworks needed (e.g., Grape, RSpec)
18
+
19
+ ## Motivation
20
+
21
+ After experiencing the interactive documentation in Python's fast-api framework, I sought similar functionality in Ruby on Rails. Unable to find a suitable solution, I [asked on Stack Overflow](https://stackoverflow.com/questions/71947018/is-there-a-way-to-generate-an-interactive-documentation-for-rails-apis) years ago. Now, with some free time while freelancing as an API developer, I decided to build my own tool.
22
+
23
+ **Note**: This is not yet a production-ready solution. The code may be rough and behave unexpectedly, but I am actively working on improving it. If you like the idea, please consider contributing to its development.
24
+
25
+ The goal is to minimize the effort required to create comprehensive documentation. By following REST principles in Rails, we believe this is achievable. You can enhance the documentation using [Yard](https://yardoc.org/) tags.
26
+
27
+ ## Installation
28
+
29
+ 1. Add this line to your Rails application's Gemfile:
30
+
31
+ ```ruby
32
+ gem "oas_rails"`
33
+ ```
34
+
35
+ 2. Execute:
36
+
37
+ ```bash
38
+ bundle
39
+ ```
40
+
41
+ 3. Mount the engine in your config/routes.rb file
42
+
43
+ ```ruby
44
+ mount OasRails::Engine => '/docs'
45
+ ```
46
+
47
+ You'll now have **basic documentation** based on your routes and automatically gathered information at `localhost:3000/docs`. To enhance it, create an initializer file and add [Yard](https://yardoc.org/) tags to your controller methods.
48
+
49
+ ## Usage
50
+
51
+ ### Initializer File
52
+
53
+ You can easy create the initializer file with:
54
+
55
+ ```
56
+ rails generate oas_rails:config
57
+ ```
58
+
59
+ Then complete the created file with your data.
60
+
61
+ **Almost every description in a OAS file support simple markdown**
62
+
63
+ ## Documenting Your Endpoints
64
+
65
+ Almost every description in an OAS file supports simple markdown. The following tags are available for documenting your endpoints:
66
+
67
+ ### @summary
68
+
69
+ **Structure**: `@summary text`
70
+
71
+ Used to add a summary to the endpoint. It replaces the default summary/title of the endpoint.
72
+
73
+ **Example**:
74
+ `# @summary This endpoint creates a User`
75
+
76
+ ### @parameter
77
+
78
+ **Structure**: `@parameter name(position) [type] text`
79
+
80
+ Represents a parameter for the endpoint. The position can be: `header`, `path`, `cookie`, or `query`. The type should be a valid Ruby class: `String`, `Integer`, `Array<String>`, etc. Add a `!` after the class to indicate a required parameter.
81
+
82
+ **Examples**:
83
+ `# @parameter page(query) [Integer] The page number.`
84
+ `# @parameter slug(path) [String!] Slug of the Project.`
85
+
86
+ ### @request_body
87
+
88
+ **Structure**: `@request_body text [type] structure`
89
+
90
+ Documents the request body needed by the endpoint. The structure is optional if you provide a valid Active Record class. Use `!` to indicate a required request body.
91
+
92
+ **Example**:
93
+ `# @request_body The user to be created [Hash] {user: {name: String, age: Integer, password: String}}`
94
+
95
+ ### @request_body_example
96
+
97
+ **Structure**: `@request_body_example text [type] structure`
98
+
99
+ Adds examples to the provided request body.
100
+
101
+ **Example**:
102
+ `# @request_body_example A complete User. [Hash] {user: {name: 'Luis', age: 30, password: 'MyWeakPassword123'}}`
103
+
104
+ ### @response
105
+
106
+ **Structure**: `@response text(code) [type] structure`
107
+
108
+ Documents the responses of the endpoint and overrides the default responses found by the engine.
109
+
110
+ **Example**:
111
+ `# @response User not found by the provided Id(404) [Hash] {success: Boolean, message: String}`
112
+
113
+ ### @tag
114
+
115
+ **Structure**: `@tag text`
116
+
117
+ Tags your endpoints. You can complete the tag documentation in the initializer file by defining these tags beforehand. It's not necessary for the tag to exist in your initializer file before use.
118
+
119
+ **Example**:
120
+ `# @tag Users`
121
+
122
+ You can use these tags in your controller methods to enhance the automatically generated documentation. Remember to use markdown formatting in your descriptions for better readability in the generated OAS document.
123
+
124
+ ## Contributing
125
+
126
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
127
+
128
+ 1. Fork the Project
129
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
130
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
131
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
132
+ 5. Open a Pull Request
133
+
134
+ ### Roadmap and Ideas for Improvement
135
+
136
+ - Clean, document and structure the code
137
+ - Support documentation of authentication methods
138
+ - Define Global Tags/Configuration (e.g., common responses like 404 errors)
139
+ - Post-process the JSON and replace common objects with references to components
140
+ - Create a temporary file with the JSON in production mode to avoid rebuilding it on every request
141
+ - Create tags for popular gems used in APIs (e.g., a `@pagy` tag for common pagination parameters)
142
+ - Add basic authentication to OAS and UI for security reasons
143
+ - Implement ability to define OAS by namespaces (e.g., generate OAS for specific routes like `/api` or separate versions V1 and V2)
144
+
145
+ ## License
146
+
147
+ The gem is available as open source under the terms of the [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.en.html#license-text).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/oas_rails .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module OasRails
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ module OasRails
2
+ class OasRailsController < ApplicationController
3
+ def index; end
4
+
5
+ def oas
6
+ render json: Specification.new.to_json, status: :ok
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module OasRails
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module OasRails
2
+ module OasRailsHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module OasRails
2
+ module TestHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module OasRails
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,6 @@
1
+ module OasRails
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module OasRails
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Oas rails</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <meta charset="utf-8">
8
+ <!-- Important: rapi-doc uses utf8 characters -->
9
+ <script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
10
+
11
+ <%= stylesheet_link_tag "oas_rails/application", media: "all" %>
12
+ </head>
13
+ <body>
14
+
15
+ <%= yield %>
16
+
17
+ </body>
18
+ </html>
@@ -0,0 +1 @@
1
+ <rapi-doc spec-url = "<%= main_app.oas_rails_path %>/oas" theme = "dark" text-color="#f9f9f9" show-header = 'false'> </rapi-doc>
@@ -0,0 +1 @@
1
+ <%= @routes %>
data/config/routes.rb ADDED
@@ -0,0 +1,4 @@
1
+ OasRails::Engine.routes.draw do
2
+ root 'oas_rails#index'
3
+ get '/oas', to: 'oas_rails#oas'
4
+ end
@@ -0,0 +1,11 @@
1
+ module OasRails
2
+ module Generators
3
+ class ConfigGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('templates', __dir__)
5
+
6
+ def copy_initializer_file
7
+ template "oas_rails_initializer.rb", "config/initializers/oas_rails.rb"
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ # config/initializers/oas_rails.rb
2
+ OasRails.configure do |config|
3
+ config.info.title = 'OasRails'
4
+ config.info.summary = 'OasRails: Automatic Interactive API Documentation for Rails'
5
+ config.info.description = <<~HEREDOC
6
+ # Welcome to OasRails
7
+
8
+ OasRails automatically generates interactive documentation for your Rails APIs using the OpenAPI Specification 3.1 (OAS 3.1) and displays it with a nice UI.
9
+
10
+ ## Getting Started
11
+
12
+ You've successfully mounted the OasRails engine. This default documentation is based on your routes and automatically gathered information.
13
+
14
+ ## Enhancing Your Documentation
15
+
16
+ To customize and enrich your API documentation:
17
+
18
+ 1. Generate an initializer file:
19
+
20
+ ```
21
+ rails generate oas_rails:config
22
+ ```
23
+ 2. Edit the created `config/initializers/oas_rails.rb` file to override default settings and add project-specific information.
24
+
25
+ 3. Use Yard tags in your controller methods to provide detailed API endpoint descriptions.
26
+
27
+ ## Features
28
+
29
+ - Automatic OAS 3.1 document generation
30
+ - [RapiDoc](https://github.com/rapi-doc/RapiDoc) integration for interactive exploration
31
+ - Minimal setup required for basic documentation
32
+ - Extensible through configuration and Yard tags
33
+
34
+ Explore your API documentation and enjoy the power of OasRails!
35
+
36
+ For more information and advanced usage, visit the [OasRails GitHub repository](https://github.com/a-chacon/oas_rails).
37
+
38
+
39
+ HEREDOC
40
+ config.info.contact.name = 'a-chacon'
41
+ config.info.contact.email = 'andres.ch@proton.me'
42
+ config.info.contact.url = 'https://a-chacon.com'
43
+ config.servers = [{ url: 'http://localhost:3000', description: 'Local' }]
44
+ config.tags = [{ name: "Users", description: "Manage the `amazing` Users table." }]
45
+
46
+ # config.default_tags_from = :namespace # Could be: :namespace or :controller
47
+ # config.request_body_automatically = true # Try to get request body for create and update methos based on the controller name.
48
+ # config.autodiscover_responses = true # Looks for renders in your source code and try to generate the responses.
49
+ end
@@ -0,0 +1,28 @@
1
+ module OasRails
2
+ class Configuration
3
+ attr_accessor :info, :default_tags_from, :request_body_automatically, :autodiscover_responses
4
+ attr_reader :servers, :tags
5
+
6
+ def initialize(**kwargs)
7
+ @info = Info.new
8
+ @servers = kwargs[:servers] || default_servers
9
+ @tags = []
10
+ @swagger_version = '3.1.0'
11
+ @default_tags_from = "namespace"
12
+ @request_body_automatically = true
13
+ @autodiscover_responses = true
14
+ end
15
+
16
+ def default_servers
17
+ [Server.new(url: "http://localhost:3000", description: "Rails Default Development Server")]
18
+ end
19
+
20
+ def servers=(value)
21
+ @servers = value.map { |s| Server.new(url: s[:url], description: s[:description]) }
22
+ end
23
+
24
+ def tags=(value)
25
+ @tags = value.map { |t| Tag.new(name: t[:name], description: t[:description]) }
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,12 @@
1
+ module OasRails
2
+ class Contact < OasBase
3
+ attr_accessor :name, :url, :email
4
+
5
+ def initialize(**kwargs)
6
+ super()
7
+ @name = kwargs[:name] || ''
8
+ @url = kwargs[:url] || ''
9
+ @email = kwargs[:email] || ''
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module OasRails
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace OasRails
4
+ end
5
+ end
@@ -0,0 +1,60 @@
1
+ module OasRails
2
+ class Info < OasBase
3
+ attr_accessor :title, :summary, :description, :terms_of_service, :contact, :license, :version
4
+
5
+ def initialize(**kwargs)
6
+ super()
7
+ @title = kwargs[:title] || default_title
8
+ @summary = kwargs[:summary] || default_summary
9
+ @description = kwargs[:description] || default_description
10
+ @terms_of_service = kwargs[:terms_of_service] || ''
11
+ @contact = Contact.new
12
+ @license = License.new
13
+ @version = kwargs[:version] || '0.0.1'
14
+ end
15
+
16
+ def default_title
17
+ "OasRails #{VERSION}"
18
+ end
19
+
20
+ def default_summary
21
+ "OasRails: Automatic Interactive API Documentation for Rails"
22
+ end
23
+
24
+ def default_description
25
+ "# Welcome to OasRails
26
+
27
+ OasRails automatically generates interactive documentation for your Rails APIs using the OpenAPI Specification 3.1 (OAS 3.1) and displays it with a nice UI.
28
+
29
+ ## Getting Started
30
+
31
+ You've successfully mounted the OasRails engine. This default documentation is based on your routes and automatically gathered information.
32
+
33
+ ## Enhancing Your Documentation
34
+
35
+ To customize and enrich your API documentation:
36
+
37
+ 1. Generate an initializer file:
38
+
39
+ ```
40
+ rails generate oas_rails:config
41
+ ```
42
+ 2. Edit the created `config/initializers/oas_rails.rb` file to override default settings and add project-specific information.
43
+
44
+ 3. Use Yard tags in your controller methods to provide detailed API endpoint descriptions.
45
+
46
+ ## Features
47
+
48
+ - Automatic OAS 3.1 document generation
49
+ - [RapiDoc](https://github.com/rapi-doc/RapiDoc) integration for interactive exploration
50
+ - Minimal setup required for basic documentation
51
+ - Extensible through configuration and Yard tags
52
+
53
+ Explore your API documentation and enjoy the power of OasRails!
54
+
55
+ For more information and advanced usage, visit the [OasRails GitHub repository](https://github.com/a-chacon/oas_rails).
56
+
57
+ "
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ module OasRails
2
+ class License < OasBase
3
+ attr_accessor :name, :url
4
+
5
+ def initialize(**kwargs)
6
+ super()
7
+ @name = kwargs[:name] || 'GPL 3.0'
8
+ @url = kwargs[:url] || 'https://www.gnu.org/licenses/gpl-3.0.html#license-text'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,57 @@
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
+ def search_for_examples_in_tests(klass:)
24
+ case OasRails.detect_test_framework
25
+ when :factory_bot
26
+ {}
27
+ # TODO: create examples with FactoryBot
28
+ when :fixtures
29
+ # Handle fixtures scenario
30
+ fixture_file = Rails.root.join('test', 'fixtures', "#{klass.to_s.pluralize.downcase}.yml")
31
+ fixture_data = YAML.load_file(fixture_file).with_indifferent_access
32
+
33
+ users_hash = {}
34
+
35
+ # Convert the fixture data to a hash
36
+ fixture_data.each do |name, attributes|
37
+ users_hash[name] = { value: { klass.to_s.downcase => attributes } }
38
+ end
39
+ users_hash
40
+ else
41
+ {}
42
+ end
43
+ end
44
+
45
+ def tags_to_examples(tags:)
46
+ tags.each_with_object({}).with_index(1) do |(example, result), _index|
47
+ key = example.text.downcase.gsub(' ', '_')
48
+ value = {
49
+ "summary" => example.text,
50
+ "value" => example.content
51
+ }
52
+ result[key] = value
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,29 @@
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
+ end
18
+ hash
19
+ end
20
+
21
+ private
22
+
23
+ def snake_to_camel(snake_str)
24
+ words = snake_str.to_s.split('_')
25
+ words[1..].map!(&:capitalize)
26
+ (words[0] + words[1..].join).to_sym
27
+ end
28
+ end
29
+ end