Skip to content
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 8 commits into from
May 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 290 additions & 0 deletions features/slate_documentation.feature
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 |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing :trollface:

Copy link
Contributor Author

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.




### cURL

<code>curl&nbsp;"http://localhost:3000/orders"&nbsp;-X&nbsp;GET&nbsp;&#92;<br>&nbsp;&nbsp;-H&nbsp;"Host:&nbsp;example.org"&nbsp;&#92;<br>&nbsp;&nbsp;-H&nbsp;"Cookie:&nbsp;"</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&nbsp;"http://localhost:3000/orders"&nbsp;-d&nbsp;'name=Order+3&amount=33.0'&nbsp;-X&nbsp;POST&nbsp;&#92;<br>&nbsp;&nbsp;-H&nbsp;"Host:&nbsp;example.org"&nbsp;&#92;<br>&nbsp;&nbsp;-H&nbsp;"Content-Type:&nbsp;application/x-www-form-urlencoded"&nbsp;&#92;<br>&nbsp;&nbsp;-H&nbsp;"Cookie:&nbsp;"</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
"""
2 changes: 2 additions & 0 deletions lib/rspec_api_documentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module Writers
autoload :IndexHelper
autoload :CombinedTextWriter
autoload :CombinedJsonWriter
autoload :SlateWriter
end

module Views
Expand All @@ -56,6 +57,7 @@ module Views
autoload :TextileExample
autoload :MarkdownIndex
autoload :MarkdownExample
autoload :SlateExample
end

def self.configuration
Expand Down
32 changes: 32 additions & 0 deletions lib/rspec_api_documentation/views/slate_example.rb
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(' ', '&nbsp;').gsub('\\', '&#92;')
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
29 changes: 29 additions & 0 deletions lib/rspec_api_documentation/writers/slate_writer.rb
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
Loading