-
Notifications
You must be signed in to change notification settings - Fork 365
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a writer for Slate #282
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
e8263e4
Set up basic structure for Slate writer. [#275]
marnen b336cf7
Install template and update feature. [#275]
marnen 5a71d28
Set up cURL output. [#275]
marnen f4b7578
Add cURL output to Cucumber scenario. [#275]
marnen 8abb266
Implement explanation_with_linebreaks. [#275]
marnen a8f2d3b
Write all examples to one file so that there's only one thing to incl…
marnen 58858da
Fix a silly mistake. [#275]
marnen b8250a2
Remove obsolete failing test. [#275]
marnen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
Feature: Generate Slate documentation from test examples | ||
|
||
Background: | ||
Given a file named "app.rb" with: | ||
""" | ||
require 'sinatra' | ||
|
||
class App < Sinatra::Base | ||
get '/orders' do | ||
content_type :json | ||
|
||
[200, { | ||
:page => 1, | ||
:orders => [ | ||
{ name: 'Order 1', amount: 9.99, description: nil }, | ||
{ name: 'Order 2', amount: 100.0, description: 'A great order' } | ||
] | ||
}.to_json] | ||
end | ||
|
||
get '/orders/:id' do | ||
content_type :json | ||
|
||
[200, { order: { name: 'Order 1', amount: 100.0, description: 'A great order' } }.to_json] | ||
end | ||
|
||
post '/orders' do | ||
201 | ||
end | ||
|
||
put '/orders/:id' do | ||
200 | ||
end | ||
|
||
delete '/orders/:id' do | ||
200 | ||
end | ||
|
||
get '/help' do | ||
[200, 'Welcome Henry !'] | ||
end | ||
end | ||
""" | ||
And a file named "app_spec.rb" with: | ||
""" | ||
require "rspec_api_documentation" | ||
require "rspec_api_documentation/dsl" | ||
|
||
RspecApiDocumentation.configure do |config| | ||
config.app = App | ||
config.api_name = "Example API" | ||
config.format = :slate | ||
config.curl_host = 'http://localhost:3000' | ||
config.request_headers_to_include = %w[Content-Type Host] | ||
config.response_headers_to_include = %w[Content-Type Content-Length] | ||
end | ||
|
||
resource 'Orders' do | ||
get '/orders' do | ||
response_field :page, "Current page" | ||
|
||
example_request 'Getting a list of orders' do | ||
status.should eq(200) | ||
response_body.should eq('{"page":1,"orders":[{"name":"Order 1","amount":9.99,"description":null},{"name":"Order 2","amount":100.0,"description":"A great order"}]}') | ||
end | ||
end | ||
|
||
get '/orders/:id' do | ||
let(:id) { 1 } | ||
|
||
example_request 'Getting a specific order' do | ||
status.should eq(200) | ||
response_body.should == '{"order":{"name":"Order 1","amount":100.0,"description":"A great order"}}' | ||
end | ||
end | ||
|
||
post '/orders' do | ||
parameter :name, 'Name of order', :required => true | ||
parameter :amount, 'Amount paid', :required => true | ||
parameter :description, 'Some comments on the order' | ||
|
||
let(:name) { "Order 3" } | ||
let(:amount) { 33.0 } | ||
|
||
example_request 'Creating an order' do | ||
status.should == 201 | ||
end | ||
end | ||
|
||
put '/orders/:id' do | ||
parameter :name, 'Name of order', :required => true | ||
parameter :amount, 'Amount paid', :required => true | ||
parameter :description, 'Some comments on the order' | ||
|
||
let(:id) { 2 } | ||
let(:name) { "Updated name" } | ||
|
||
example_request 'Updating an order' do | ||
status.should == 200 | ||
end | ||
end | ||
|
||
delete "/orders/:id" do | ||
let(:id) { 1 } | ||
|
||
example_request "Deleting an order" do | ||
status.should == 200 | ||
end | ||
end | ||
end | ||
|
||
resource 'Help' do | ||
get '/help' do | ||
example_request 'Getting welcome message' do | ||
status.should eq(200) | ||
response_body.should == 'Welcome Henry !' | ||
end | ||
end | ||
|
||
end | ||
""" | ||
When I run `rspec app_spec.rb --require ./app.rb --format RspecApiDocumentation::ApiFormatter` | ||
|
||
Scenario: Output helpful progress to the console | ||
Then the output should contain: | ||
""" | ||
Generating API Docs | ||
Orders | ||
GET /orders | ||
* Getting a list of orders | ||
GET /orders/:id | ||
* Getting a specific order | ||
POST /orders | ||
* Creating an order | ||
PUT /orders/:id | ||
* Updating an order | ||
DELETE /orders/:id | ||
* Deleting an order | ||
Help | ||
GET /help | ||
* Getting welcome message | ||
""" | ||
And the output should contain "6 examples, 0 failures" | ||
And the exit status should be 0 | ||
|
||
Scenario: Example 'Getting a list of orders' docs should look like we expect | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Getting a list of orders | ||
|
||
### Request | ||
|
||
#### Endpoint | ||
|
||
``` | ||
GET /orders | ||
Host: example.org | ||
``` | ||
|
||
`GET /orders` | ||
|
||
|
||
#### Parameters | ||
|
||
|
||
None known. | ||
|
||
|
||
### Response | ||
|
||
``` | ||
Content-Type: application/json | ||
Content-Length: 137 | ||
200 OK | ||
``` | ||
|
||
|
||
```json | ||
{ | ||
"page": 1, | ||
"orders": [ | ||
{ | ||
"name": "Order 1", | ||
"amount": 9.99, | ||
"description": null | ||
}, | ||
{ | ||
"name": "Order 2", | ||
"amount": 100.0, | ||
"description": "A great order" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
|
||
|
||
#### Fields | ||
|
||
| Name | Description | | ||
|:-----------|:--------------------| | ||
| page | Current page | | ||
|
||
|
||
|
||
### cURL | ||
|
||
<code>curl "http://localhost:3000/orders" -X GET \<br> -H "Host: example.org" \<br> -H "Cookie: "</code> | ||
""" | ||
|
||
Scenario: Example 'Creating an order' docs should look like we expect | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Creating an order | ||
|
||
### Request | ||
|
||
#### Endpoint | ||
|
||
``` | ||
POST /orders | ||
Host: example.org | ||
Content-Type: application/x-www-form-urlencoded | ||
``` | ||
|
||
`POST /orders` | ||
|
||
|
||
#### Parameters | ||
|
||
|
||
```json | ||
name=Order+3&amount=33.0 | ||
``` | ||
|
||
|
||
| Name | Description | | ||
|:-----|:------------| | ||
| name *required* | Name of order | | ||
| amount *required* | Amount paid | | ||
| description | Some comments on the order | | ||
|
||
|
||
|
||
### Response | ||
|
||
``` | ||
Content-Type: text/html;charset=utf-8 | ||
Content-Length: 0 | ||
201 Created | ||
``` | ||
|
||
|
||
|
||
|
||
|
||
### cURL | ||
|
||
<code>curl "http://localhost:3000/orders" -d 'name=Order+3&amount=33.0' -X POST \<br> -H "Host: example.org" \<br> -H "Content-Type: application/x-www-form-urlencoded" \<br> -H "Cookie: "</code> | ||
""" | ||
|
||
Scenario: Example 'Deleting an order' docs should be created | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Deleting an order | ||
""" | ||
|
||
Scenario: Example 'Getting a list of orders' docs should be created | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Getting a list of orders | ||
""" | ||
|
||
Scenario: Example 'Getting a specific order' docs should be created | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Getting a specific order | ||
""" | ||
|
||
Scenario: Example 'Updating an order' docs should be created | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Updating an order | ||
""" | ||
|
||
Scenario: Example 'Getting welcome message' docs should be created | ||
Then the file "doc/api/_generated_examples.markdown" should contain: | ||
""" | ||
## Getting welcome message | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module RspecApiDocumentation | ||
module Views | ||
class SlateExample < MarkdownExample | ||
def initialize(example, configuration) | ||
super | ||
self.template_name = "rspec_api_documentation/slate_example" | ||
end | ||
|
||
def curl_with_linebreaks | ||
requests.map {|request| request[:curl].lines }.flatten.map do |line| | ||
line.rstrip.gsub("\t", ' ').gsub(' ', ' ').gsub('\\', '\') | ||
end.join "<br>" | ||
end | ||
|
||
def explanation_with_linebreaks | ||
explanation.gsub "\n", "<br>\n" | ||
end | ||
|
||
def write | ||
File.open(configuration.docs_dir.join("#{FILENAME}.#{extension}"), 'w+') do |file| | ||
file.write "# #{configuration.api_name}\n\n" | ||
index.examples.sort_by!(&:description) unless configuration.keep_source_order | ||
|
||
index.examples.each do |example| | ||
markup_example = markup_example_class.new(example, configuration) | ||
file.write markup_example.render | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
module RspecApiDocumentation | ||
module Writers | ||
|
||
class SlateWriter < MarkdownWriter | ||
FILENAME = '_generated_examples' | ||
|
||
def self.clear_docs(docs_dir) | ||
FileUtils.mkdir_p(docs_dir) | ||
FileUtils.rm Dir[File.join docs_dir, "#{FILENAME}.*"] | ||
end | ||
|
||
def markup_example_class | ||
RspecApiDocumentation::Views::SlateExample | ||
end | ||
|
||
def write | ||
File.open(configuration.docs_dir.join("#{FILENAME}.#{extension}"), 'w+') do |file| | ||
file.write "# #{configuration.api_name}\n\n" | ||
index.examples.sort_by!(&:description) unless configuration.keep_source_order | ||
|
||
index.examples.each do |example| | ||
markup_example = markup_example_class.new(example, configuration) | ||
file.write markup_example.render | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spacing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know the spacing is funny, but spacing out the Markdown table would have been a lot of work for no real gain. Look at slate_example.mustache and you'll see what I mean.