Skip to content

Commit e1eb984

Browse files
authored
Merge pull request #6 from drewish/rename-rspec-rails-swagger
Rename to rspec-rails-swagger
2 parents c6b2d18 + 5e1f415 commit e1eb984

25 files changed

+583
-569
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# RSpec Swagger
22

3-
[![Build Status](https://travis-ci.org/drewish/rspec-swagger.svg?branch=master)](https://travis-ci.org/drewish/rspec-swagger)
4-
[![Code Climate](https://codeclimate.com/github/drewish/rspec-swagger/badges/gpa.svg)](https://codeclimate.com/github/drewish/rspec-swagger)
3+
[![Build Status](https://travis-ci.org/drewish/rspec-rails-swagger.svg?branch=master)](https://travis-ci.org/drewish/rspec-rails-swagger)
4+
[![Code Climate](https://codeclimate.com/github/drewish/rspec-rails-swagger/badges/gpa.svg)](https://codeclimate.com/github/drewish/rspec-rails-swagger)
55

66
This gem helps you generate Swagger docs by using RSpec to document the paths.
77
You execute a command to run the tests and generate the `.json` output. Running
@@ -15,15 +15,15 @@ The design of this was heavily influenced by the awesome [swagger_rails gem](htt
1515
- Add the gem to your Rails app's `Gemfile`:
1616
```rb
1717
group :development, :test do
18-
gem 'rspec-swagger'
18+
gem 'rspec-rails-swagger'
1919
end
2020
```
2121
- If you don't already have a `spec/rails_helper.rb` file run:
2222
```shell
2323
rails generate rspec:install
2424
```
2525
- Create `spec/swagger_helper.rb` file (eventually [this will become a
26-
generator](https://github.com/drewish/rspec-swagger/issues/3)):
26+
generator](https://github.com/drewish/rspec-rails-swagger/issues/3)):
2727
```rb
2828
require 'rspec/swagger'
2929
require 'rails_helper'
@@ -55,7 +55,7 @@ end
5555

5656
## Generate the docs
5757

58-
Eventually [this will become a rake task](https://github.com/drewish/rspec-swagger/issues/2):
58+
Eventually [this will become a rake task](https://github.com/drewish/rspec-rails-swagger/issues/2):
5959
```
6060
bundle exec rspec -f RSpec::Swagger::Formatter --order defined -t swagger_object
6161
```

lib/rspec/rails/swagger.rb

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require 'rspec/core'
2+
require 'rspec/rails/swagger/configuration'
3+
require 'rspec/rails/swagger/document'
4+
require 'rspec/rails/swagger/formatter'
5+
require 'rspec/rails/swagger/helpers'
6+
require 'rspec/rails/swagger/request_builder'
7+
require 'rspec/rails/swagger/version'
8+
9+
module RSpec
10+
module Rails
11+
module Swagger
12+
initialize_configuration RSpec.configuration
13+
end
14+
end
15+
end
16+
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module RSpec
2+
module Rails
3+
module Swagger
4+
# Fake class to document RSpec Swagger configuration options.
5+
class Configuration
6+
end
7+
8+
def self.initialize_configuration(config)
9+
config.add_setting :swagger_root
10+
config.add_setting :swagger_docs, default: {}
11+
12+
Helpers.add_swagger_type_configurations(config)
13+
end
14+
end
15+
end
16+
end

lib/rspec/rails/swagger/document.rb

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module RSpec
2+
module Rails
3+
module Swagger
4+
class Document
5+
attr_accessor :data
6+
7+
def initialize(data)
8+
@data = data.deep_symbolize_keys
9+
end
10+
11+
def [](value)
12+
data[value]
13+
end
14+
15+
def resolve_ref(ref)
16+
unless %r{#/(?<location>parameters|definitions)/(?<name>.+)} =~ ref
17+
raise ArgumentError, "Invalid reference: #{ref}"
18+
end
19+
20+
result = data.fetch(location.to_sym, {})[name.to_sym]
21+
raise ArgumentError, "Reference value does not exist: #{ref}" unless result
22+
23+
if location == 'parameters'
24+
result.merge(name: name)
25+
end
26+
27+
result
28+
end
29+
end
30+
end
31+
end
32+
end

lib/rspec/rails/swagger/formatter.rb

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
require 'rspec/core/formatters/base_text_formatter'
2+
3+
module RSpec
4+
module Rails
5+
module Swagger
6+
class Formatter < RSpec::Core::Formatters::BaseTextFormatter
7+
RSpec::Core::Formatters.register self, :example_finished, :close
8+
9+
def documents
10+
# We don't try to load the docs in `initalize` because when running
11+
# `rspec -f RSpec::Swagger::Formatter` RSpec initalized this class
12+
# before `swagger_helper` has run.
13+
@documents ||= ::RSpec.configuration.swagger_docs
14+
end
15+
16+
def example_finished(notification)
17+
metadata = notification.example.metadata
18+
return unless metadata[:swagger_object] == :response
19+
20+
# metadata.each do |k, v|
21+
# puts "#{k}\t#{v}" if k.to_s.starts_with?("swagger")
22+
# end
23+
24+
document = document_for(metadata[:swagger_document])
25+
path_item = path_item_for(document, metadata[:swagger_path_item])
26+
operation = operation_for(path_item, metadata[:swagger_operation])
27+
response_for(operation, metadata[:swagger_response])
28+
end
29+
30+
def close(_notification)
31+
documents.each{|k, v| write_json(k, v)}
32+
end
33+
34+
def write_json(name, document)
35+
root = ::RSpec.configuration.swagger_root
36+
# It would be good to at least warn if the name includes some '../' that
37+
# takes it out of root directory.
38+
target = Pathname(name).expand_path(root)
39+
target.dirname.mkpath
40+
target.write(JSON.pretty_generate(document))
41+
end
42+
43+
def document_for(doc_name = nil)
44+
if doc_name
45+
documents.fetch(doc_name)
46+
else
47+
documents.values.first
48+
end
49+
end
50+
51+
def path_item_for(document, swagger_path_item)
52+
name = swagger_path_item[:path]
53+
54+
document[:paths] ||= {}
55+
document[:paths][name] ||= {}
56+
if swagger_path_item[:parameters]
57+
document[:paths][name][:parameters] = prepare_parameters(swagger_path_item[:parameters])
58+
end
59+
document[:paths][name]
60+
end
61+
62+
def operation_for(path, swagger_operation)
63+
method = swagger_operation[:method]
64+
65+
path[method] ||= {responses: {}}
66+
path[method].tap do |operation|
67+
if swagger_operation[:parameters]
68+
operation[:parameters] = prepare_parameters(swagger_operation[:parameters])
69+
end
70+
operation.merge!(swagger_operation.slice(
71+
:summary, :description, :externalDocs, :operationId,
72+
:consumes, :produces, :schemes, :deprecated, :security
73+
))
74+
end
75+
end
76+
77+
def response_for(operation, swagger_response)
78+
status = swagger_response[:status_code]
79+
80+
operation[:responses][status] ||= {}
81+
operation[:responses][status].tap do |response|
82+
if swagger_response[:examples]
83+
response[:examples] = prepare_examples(swagger_response[:examples])
84+
end
85+
response.merge!(swagger_response.slice(:description, :schema, :headers))
86+
end
87+
end
88+
89+
def prepare_parameters(params)
90+
params.values
91+
end
92+
93+
def prepare_examples(examples)
94+
if examples["application/json"].present?
95+
begin
96+
examples["application/json"] = JSON.parse(examples["application/json"])
97+
rescue JSON::ParserError
98+
end
99+
end
100+
examples
101+
end
102+
end
103+
end
104+
end
105+
end

0 commit comments

Comments
 (0)