Commit 2921b770 by andrew morton Committed by GitHub

Merge pull request #14 from drewish/spec-generator

Generate Swagger spec for a controller
parents b34a4681 539c9055
...@@ -51,7 +51,12 @@ RSpec.configure do |config| ...@@ -51,7 +51,12 @@ RSpec.configure do |config|
} }
end end
``` ```
- Define your API (I definitely need to make this step more explicit) - Use the generator to help create a Swagger request spec. Running:
```
rails generate rspec:swagger PostsController
```
will give you a nice starting point with paths and operations for each method
in the controller.
## Generate the docs ## Generate the docs
......
Description:
This creates an RSpec request spec to define Swagger documentation for a
controller. It will create a test for each of the controller's methods.
Example:
rails generate rspec:swagger V3::AccountsController
This will create:
spec/requests/v3/accounts_spec.rb
require 'rails/generators'
module Rspec
module Generators
class SwaggerGenerator < ::Rails::Generators::NamedBase
source_root File.expand_path('../templates', __FILE__)
def setup
@routes = RSpec::Rails::Swagger::RouteParser.new(controller_path).routes
end
def create_spec_file
template 'spec.rb', File.join('spec/requests', "#{controller_path}_spec.rb")
end
private
def controller_path
file_path.chomp('_controller')
end
end
end
end
require 'swagger_helper'
RSpec.describe '<%= file_name %>', type: :request do
<% @routes.each do | template, path_item | %>
path '<%= template %>' do
<% unless path_item[:params].empty? -%>
# You'll want to customize the parameter types...
<% path_item[:params].each do |param| -%>
parameter '<%= param %>', in: :path, type: :string
<% end -%>
# ...and values used to make the requests.
<% path_item[:params].each do |param| -%>
let(:<%= param %>) { '123' }
<% end -%>
<% end -%>
<% path_item[:actions].each do | action, details | -%>
<%= action %>(summary: '<%= details[:summary] %>') do
response(200, description: 'successful') do
# You can add before/let blocks here to trigger the response code
end
end
<% end -%>
end
<% end -%>
end
...@@ -4,6 +4,7 @@ require 'rspec/rails/swagger/document' ...@@ -4,6 +4,7 @@ require 'rspec/rails/swagger/document'
require 'rspec/rails/swagger/formatter' require 'rspec/rails/swagger/formatter'
require 'rspec/rails/swagger/helpers' require 'rspec/rails/swagger/helpers'
require 'rspec/rails/swagger/request_builder' require 'rspec/rails/swagger/request_builder'
require 'rspec/rails/swagger/route_parser'
require 'rspec/rails/swagger/version' require 'rspec/rails/swagger/version'
module RSpec module RSpec
...@@ -16,6 +17,9 @@ module RSpec ...@@ -16,6 +17,9 @@ module RSpec
rake_tasks do rake_tasks do
load 'rspec/rails/swagger/tasks/swagger.rake' load 'rspec/rails/swagger/tasks/swagger.rake'
end end
generators do
require "generators/rspec/swagger/swagger_generator.rb"
end
end end
end end
end end
......
module RSpec
module Rails
module Swagger
class RouteParser
attr_reader :controller
def initialize(controller)
@controller = controller
end
def routes
::Rails.application.routes.routes.select do |route|
route.defaults[:controller] == controller
end.reduce({}) do |tree, route|
path = path_from(route)
verb = verb_from(route)
tree[path] ||= { params: params_from(route), actions: {} }
tree[path][:actions][verb] = { summary: summary_from(route) }
tree
end
end
private
def path_from(route)
route.path.spec.to_s
.chomp('(.:format)') # Ignore any format suffix
.gsub(/:([^\/.?]+)/, '{\1}') # Convert :id to {id}
end
def verb_from(route)
verb = route.verb
if verb.kind_of? String
verb.downcase
else
verb.source.gsub(/[$^]/, '').downcase
end
end
def summary_from(route)
verb = route.requirements[:action]
noun = route.requirements[:controller].split('/').last.singularize
# Apply a few customizations to make things more readable
case verb
when 'index'
verb = 'list'
noun = noun.pluralize
when 'destroy'
verb = 'delete'
end
"#{verb} #{noun}"
end
def params_from(route)
route.segments - ['format']
end
end
end
end
end
...@@ -9,16 +9,7 @@ Gem::Specification.new do |s| ...@@ -9,16 +9,7 @@ Gem::Specification.new do |s|
s.description = "Inspired by swagger_rails" s.description = "Inspired by swagger_rails"
s.author = "andrew morton" s.author = "andrew morton"
s.email = 'drewish@katherinehouse.com' s.email = 'drewish@katherinehouse.com'
s.files = [ s.files = Dir['*.md', '*.txt', 'lib/**/*']
'lib/rspec/rails/swagger.rb',
'lib/rspec/rails/swagger/configuration.rb',
'lib/rspec/rails/swagger/document.rb',
'lib/rspec/rails/swagger/formatter.rb',
'lib/rspec/rails/swagger/helpers.rb',
'lib/rspec/rails/swagger/request_builder.rb',
'lib/rspec/rails/swagger/version.rb',
'lib/rspec/rails/swagger/tasks/swagger.rake',
]
s.homepage = 'https://github.com/drewish/rspec-rails-swagger' s.homepage = 'https://github.com/drewish/rspec-rails-swagger'
s.required_ruby_version = '~> 2.0' s.required_ruby_version = '~> 2.0'
......
require 'swagger_helper'
RSpec.describe RSpec::Rails::Swagger::RouteParser do
subject { described_class.new(controller) }
describe '#routes' do
let(:controller) { 'posts' }
it 'extracts the relevant details' do
output = subject.routes
expect(output.keys).to include('/posts', '/posts/{id}')
expect(output['/posts'][:actions].keys).to include('get', 'post')
expect(output['/posts'][:actions]['get']).to eq(summary: 'list posts')
expect(output['/posts'][:actions]['post']).to eq(summary: 'create post')
expect(output['/posts/{id}'][:actions]['delete']).to eq(summary: 'delete post')
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment