Skip to content

Commit f67d57f

Browse files
committed
Merge pull request #120 from pitchtarget/markdown-format
Add support for Markdown format
2 parents 26d85fb + 150cf07 commit f67d57f

File tree

9 files changed

+395
-1
lines changed

9 files changed

+395
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ RspecApiDocumentation.configure do |config|
8484

8585
# An array of output format(s).
8686
# Possible values are :json, :html, :combined_text, :combined_json,
87-
# :json_iodocs, :textile, :append_json
87+
# :json_iodocs, :textile, :markdown, :append_json
8888
config.format = [:html]
8989

9090
# Location of templates
@@ -145,6 +145,7 @@ end
145145
* **combined_json**: Generates a single file for all examples.
146146
* **json_iodocs**: Generates [I/O Docs](http://www.mashery.com/product/io-docs) style documentation.
147147
* **textile**: Generates an index file and example files in Textile.
148+
* **markdown**: Generates an index file and example files in Markdown.
148149
* **append_json**: Lets you selectively run specs without destroying current documentation. See section below.
149150

150151
### append_json
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
Feature: Generate Markdown documentation from test examples
2+
3+
Background:
4+
Given a file named "app.rb" with:
5+
"""
6+
require 'sinatra'
7+
8+
class App < Sinatra::Base
9+
get '/orders' do
10+
content_type :json
11+
12+
[200, [{ name: 'Order 1', amount: 9.99, description: nil },
13+
{ name: 'Order 2', amount: 100.0, description: 'A great order' }].to_json]
14+
end
15+
16+
get '/orders/:id' do
17+
content_type :json
18+
19+
[200, { order: { name: 'Order 1', amount: 100.0, description: 'A great order' } }.to_json]
20+
end
21+
22+
post '/orders' do
23+
201
24+
end
25+
26+
put '/orders/:id' do
27+
200
28+
end
29+
30+
delete '/orders/:id' do
31+
200
32+
end
33+
34+
get '/help' do
35+
[200, 'Welcome Henry !']
36+
end
37+
end
38+
"""
39+
And a file named "app_spec.rb" with:
40+
"""
41+
require "rspec_api_documentation"
42+
require "rspec_api_documentation/dsl"
43+
44+
RspecApiDocumentation.configure do |config|
45+
config.app = App
46+
config.api_name = "Example API"
47+
config.format = :markdown
48+
config.request_headers_to_include = %w[Content-Type Host]
49+
config.response_headers_to_include = %w[Content-Type Content-Length]
50+
end
51+
52+
resource 'Orders' do
53+
get '/orders' do
54+
55+
example_request 'Getting a list of orders' do
56+
status.should eq(200)
57+
response_body.should eq('[{"name":"Order 1","amount":9.99,"description":null},{"name":"Order 2","amount":100.0,"description":"A great order"}]')
58+
end
59+
end
60+
61+
get '/orders/:id' do
62+
let(:id) { 1 }
63+
64+
example_request 'Getting a specific order' do
65+
status.should eq(200)
66+
response_body.should == '{"order":{"name":"Order 1","amount":100.0,"description":"A great order"}}'
67+
end
68+
end
69+
70+
post '/orders' do
71+
parameter :name, 'Name of order', :required => true
72+
parameter :amount, 'Amount paid', :required => true
73+
parameter :description, 'Some comments on the order'
74+
75+
let(:name) { "Order 3" }
76+
let(:amount) { 33.0 }
77+
78+
example_request 'Creating an order' do
79+
status.should == 201
80+
end
81+
end
82+
83+
put '/orders/:id' do
84+
parameter :name, 'Name of order', :required => true
85+
parameter :amount, 'Amount paid', :required => true
86+
parameter :description, 'Some comments on the order'
87+
88+
let(:id) { 2 }
89+
let(:name) { "Updated name" }
90+
91+
example_request 'Updating an order' do
92+
status.should == 200
93+
end
94+
end
95+
96+
delete "/orders/:id" do
97+
let(:id) { 1 }
98+
99+
example_request "Deleting an order" do
100+
status.should == 200
101+
end
102+
end
103+
end
104+
105+
resource 'Help' do
106+
get '/help' do
107+
example_request 'Getting welcome message' do
108+
status.should eq(200)
109+
response_body.should == 'Welcome Henry !'
110+
end
111+
end
112+
113+
end
114+
"""
115+
When I run `rspec app_spec.rb --require ./app.rb --format RspecApiDocumentation::ApiFormatter`
116+
117+
Scenario: Output helpful progress to the console
118+
Then the output should contain:
119+
"""
120+
Generating API Docs
121+
Orders
122+
GET /orders
123+
* Getting a list of orders
124+
GET /orders/:id
125+
* Getting a specific order
126+
POST /orders
127+
* Creating an order
128+
PUT /orders/:id
129+
* Updating an order
130+
DELETE /orders/:id
131+
* Deleting an order
132+
Help
133+
GET /help
134+
* Getting welcome message
135+
"""
136+
And the output should contain "6 examples, 0 failures"
137+
And the exit status should be 0
138+
139+
Scenario: Index file should look like we expect
140+
Then the file "doc/api/index.markdown" should contain exactly:
141+
"""
142+
# Example API
143+
144+
## Help
145+
146+
* [Getting welcome message](help/getting_welcome_message.markdown)
147+
148+
## Orders
149+
150+
* [Creating an order](orders/creating_an_order.markdown)
151+
* [Deleting an order](orders/deleting_an_order.markdown)
152+
* [Getting a list of orders](orders/getting_a_list_of_orders.markdown)
153+
* [Getting a specific order](orders/getting_a_specific_order.markdown)
154+
* [Updating an order](orders/updating_an_order.markdown)
155+
156+
157+
"""
158+
159+
Scenario: Example 'Creating an order' file should look like we expect
160+
Then the file "doc/api/orders/creating_an_order.markdown" should contain exactly:
161+
"""
162+
# Orders API
163+
164+
## Creating an order
165+
166+
### POST /orders
167+
168+
169+
### Parameters
170+
171+
Name : name *- required -*
172+
Description : Name of order
173+
174+
Name : amount *- required -*
175+
Description : Amount paid
176+
177+
Name : description
178+
Description : Some comments on the order
179+
180+
### Request
181+
182+
#### Headers
183+
184+
<pre>Host: example.org
185+
Content-Type: application/x-www-form-urlencoded</pre>
186+
187+
#### Route
188+
189+
<pre>POST /orders</pre>
190+
191+
192+
#### Body
193+
194+
<pre>name=Order+3&amount=33.0</pre>
195+
196+
197+
### Response
198+
199+
#### Headers
200+
201+
<pre>Content-Type: text/html;charset=utf-8
202+
Content-Length: 0</pre>
203+
204+
#### Status
205+
206+
<pre>201 Created</pre>
207+
208+
209+
210+
211+
"""
212+
213+
Scenario: Example 'Deleting an order' file should be created
214+
Then a file named "doc/api/orders/deleting_an_order.markdown" should exist
215+
216+
Scenario: Example 'Getting a list of orders' file should be created
217+
Then a file named "doc/api/orders/getting_a_list_of_orders.markdown" should exist
218+
219+
Scenario: Example 'Getting a specific order' file should be created
220+
Then a file named "doc/api/orders/getting_a_specific_order.markdown" should exist
221+
222+
Scenario: Example 'Updating an order' file should be created
223+
Then a file named "doc/api/orders/updating_an_order.markdown" should exist
224+
225+
Scenario: Example 'Getting welcome message' file should be created
226+
Then a file named "doc/api/help/getting_welcome_message.markdown" should exist
227+
228+

lib/rspec_api_documentation.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ module Writers
3232
autoload :GeneralMarkupWriter
3333
autoload :HtmlWriter
3434
autoload :TextileWriter
35+
autoload :MarkdownWriter
3536
autoload :JsonWriter
3637
autoload :AppendJsonWriter
3738
autoload :JsonIodocsWriter
@@ -49,6 +50,8 @@ module Views
4950
autoload :HtmlExample
5051
autoload :TextileIndex
5152
autoload :TextileExample
53+
autoload :MarkdownIndex
54+
autoload :MarkdownExample
5255
end
5356

5457
def self.configuration
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module RspecApiDocumentation
2+
module Views
3+
class MarkdownExample < MarkupExample
4+
EXTENSION = 'markdown'
5+
6+
def initialize(example, configuration)
7+
super
8+
self.template_name = "rspec_api_documentation/markdown_example"
9+
end
10+
11+
def extension
12+
EXTENSION
13+
end
14+
end
15+
end
16+
end
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
module RspecApiDocumentation
2+
module Views
3+
class MarkdownIndex < MarkupIndex
4+
def initialize(index, configuration)
5+
super
6+
self.template_name = "rspec_api_documentation/markdown_index"
7+
end
8+
9+
def examples
10+
@index.examples.map { |example| MarkdownExample.new(example, @configuration) }
11+
end
12+
end
13+
end
14+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module RspecApiDocumentation
2+
module Writers
3+
class MarkdownWriter < GeneralMarkupWriter
4+
EXTENSION = 'markdown'
5+
6+
def markup_index_class
7+
RspecApiDocumentation::Views::MarkdownIndex
8+
end
9+
10+
def markup_example_class
11+
RspecApiDocumentation::Views::MarkdownExample
12+
end
13+
14+
def extension
15+
EXTENSION
16+
end
17+
end
18+
end
19+
end

spec/writers/markdown_writer_spec.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -*- coding: utf-8 -*-
2+
require 'spec_helper'
3+
4+
describe RspecApiDocumentation::Writers::MarkdownWriter do
5+
let(:index) { RspecApiDocumentation::Index.new }
6+
let(:configuration) { RspecApiDocumentation::Configuration.new }
7+
8+
describe ".write" do
9+
let(:writer) { double(:writer) }
10+
11+
it "should build a new writer and write the docs" do
12+
described_class.stub(:new).with(index, configuration).and_return(writer)
13+
writer.should_receive(:write)
14+
described_class.write(index, configuration)
15+
end
16+
end
17+
18+
describe "#write" do
19+
let(:writer) { described_class.new(index, configuration) }
20+
21+
before do
22+
template_dir = File.join(configuration.template_path, "rspec_api_documentation")
23+
FileUtils.mkdir_p(template_dir)
24+
File.open(File.join(template_dir, "markdown_index.mustache"), "w+") { |f| f << "{{ mustache }}" }
25+
FileUtils.mkdir_p(configuration.docs_dir)
26+
end
27+
28+
it "should write the index" do
29+
writer.write
30+
index_file = File.join(configuration.docs_dir, "index.markdown")
31+
File.exists?(index_file).should be_true
32+
end
33+
end
34+
35+
end

0 commit comments

Comments
 (0)