apidoc 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -7,6 +7,7 @@ gem 'thor'
7
7
  gem 'mustache'
8
8
  gem 'rack-test'
9
9
  gem 'mustache'
10
+ gem 'kramdown'
10
11
 
11
12
  # Add dependencies to develop your gem here.
12
13
  # Include everything needed to run rake, tests, features, etc.
@@ -9,6 +9,7 @@ GEM
9
9
  rake
10
10
  rdoc
11
11
  json (1.7.3)
12
+ kramdown (0.13.5)
12
13
  mustache (0.99.4)
13
14
  rack (1.4.0)
14
15
  rack-protection (1.2.0)
@@ -40,6 +41,7 @@ DEPENDENCIES
40
41
  bundler (~> 1.0.0)
41
42
  jeweler (~> 1.8.3)
42
43
  json
44
+ kramdown
43
45
  mustache
44
46
  rack-test
45
47
  rdoc (~> 3.12)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "apidoc"
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["T.J. VanSlyke"]
12
- s.date = "2012-06-04"
12
+ s.date = "2012-06-05"
13
13
  s.description = "Minimalist API documentation generator for Rack applications."
14
14
  s.email = "tj@turing.com"
15
15
  s.executables = ["apidoc"]
@@ -36,7 +36,10 @@ Gem::Specification.new do |s|
36
36
  "ftags",
37
37
  "lib/apidoc.rb",
38
38
  "spec/apidoc_spec.rb",
39
+ "spec/before_and_after_spec.rb",
40
+ "spec/html_writer_spec.rb",
39
41
  "spec/spec_helper.rb",
42
+ "spec/support/test_apps.rb",
40
43
  "templates/apidoc_helper.rb",
41
44
  "templates/layout.mustache",
42
45
  "templates/resource.mustache"
@@ -55,6 +58,7 @@ Gem::Specification.new do |s|
55
58
  s.add_runtime_dependency(%q<mustache>, [">= 0"])
56
59
  s.add_runtime_dependency(%q<rack-test>, [">= 0"])
57
60
  s.add_runtime_dependency(%q<mustache>, [">= 0"])
61
+ s.add_runtime_dependency(%q<kramdown>, [">= 0"])
58
62
  s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
59
63
  s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
60
64
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -66,6 +70,7 @@ Gem::Specification.new do |s|
66
70
  s.add_dependency(%q<mustache>, [">= 0"])
67
71
  s.add_dependency(%q<rack-test>, [">= 0"])
68
72
  s.add_dependency(%q<mustache>, [">= 0"])
73
+ s.add_dependency(%q<kramdown>, [">= 0"])
69
74
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
70
75
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
71
76
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -78,6 +83,7 @@ Gem::Specification.new do |s|
78
83
  s.add_dependency(%q<mustache>, [">= 0"])
79
84
  s.add_dependency(%q<rack-test>, [">= 0"])
80
85
  s.add_dependency(%q<mustache>, [">= 0"])
86
+ s.add_dependency(%q<kramdown>, [">= 0"])
81
87
  s.add_dependency(%q<rspec>, ["~> 2.8.0"])
82
88
  s.add_dependency(%q<rdoc>, ["~> 3.12"])
83
89
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
@@ -108,21 +108,20 @@
108
108
  font-size: 1em;
109
109
  }
110
110
 
111
- .api-resource .desc {
112
- margin: 1em 0;
113
- color:
114
- #333;
115
- display: block;
116
- font-family: Helvetica, sans-serif;
117
- font-size: 13px;
118
- font-style: normal;
119
- font-weight: 100;
120
- height: 17px;
121
- line-height: 17px;
122
- text-shadow:
123
- rgba(255, 255, 255, 0.597656) 0px 1px 0px;
124
- vertical-align: baseline;
125
- }
111
+ .api-resource .desc {
112
+ margin: 1em 0;
113
+ color:
114
+ #333;
115
+ display: block;
116
+ font-family: Helvetica, sans-serif;
117
+ font-size: 13px;
118
+ font-weight: 100;
119
+ height: 17px;
120
+ line-height: 17px;
121
+ text-shadow:
122
+ rgba(255, 255, 255, 0.597656) 0px 1px 0px;
123
+ vertical-align: baseline;
124
+ }
126
125
  .api-resource .params,
127
126
  .api-resource .response {
128
127
  font-family: Monaco, fixed;
@@ -159,7 +158,8 @@
159
158
  <div class="api-resource">
160
159
  <div class="method">GET</div>
161
160
  <div class="path">/burritos.json</div>
162
- <div class="desc">Get all burritos</div>
161
+ <div class="desc"><p>Get all burritos. <em>Note:</em> When requesting all burritos, please give the commissary ample time to prepare your order. Fattie.</p>
162
+ </div>
163
163
  <div class="params"></div>
164
164
  <div class="response">[
165
165
  {
@@ -173,7 +173,8 @@
173
173
  <div class="api-resource">
174
174
  <div class="method">POST</div>
175
175
  <div class="path">/burritos.json</div>
176
- <div class="desc">Make a new delicious burrito</div>
176
+ <div class="desc"><p>Make a new delicious burrito</p>
177
+ </div>
177
178
  <div class="params">{
178
179
  &quot;meat&quot;: &quot;beef&quot;,
179
180
  &quot;lettuce&quot;: true
@@ -182,6 +183,18 @@
182
183
  &quot;meat&quot;: &quot;beef&quot;,
183
184
  &quot;lettuce&quot;: true
184
185
  }</div>
186
+ </div>
187
+ <div class="api-resource">
188
+ <div class="method">GET</div>
189
+ <div class="path">/burritos/:id.json</div>
190
+ <div class="desc"><p>Get a burrito by its ID</p>
191
+ </div>
192
+ <div class="params">{
193
+ }</div>
194
+ <div class="response">{
195
+ &quot;meat&quot;: &quot;beef&quot;,
196
+ &quot;id&quot;: &quot;123&quot;
197
+ }</div>
185
198
  </div>
186
199
 
187
200
  </div>
@@ -13,6 +13,10 @@ class BurritoApp < Sinatra::Base
13
13
  request.body
14
14
  end
15
15
 
16
+ get '/burritos/:id.json' do
17
+ JSON.generate({ meat: 'beef', id: params['id'] })
18
+ end
19
+
16
20
  end
17
21
 
18
22
  doc = ApiDoc.new BurritoApp do
@@ -21,13 +25,20 @@ doc = ApiDoc.new BurritoApp do
21
25
  content_type :json
22
26
 
23
27
  get '/burritos.json' do
24
- desc "Get all burritos"
28
+ desc %{Get all burritos. *Note:* When requesting all burritos, please give the commissary ample time to prepare your order. Fattie.}
25
29
  end
26
30
 
27
31
  post '/burritos.json' do
28
32
  desc "Make a new delicious burrito"
29
33
  params do
30
- JSON.generate({ meat: 'beef', lettuce: true })
34
+ { meat: 'beef', lettuce: true }
35
+ end
36
+ end
37
+
38
+ get '/burritos/:id.json' do
39
+ desc "Get a burrito by its ID"
40
+ params do
41
+ { id: 123 }
31
42
  end
32
43
  end
33
44
 
@@ -108,21 +108,20 @@
108
108
  font-size: 1em;
109
109
  }
110
110
 
111
- .api-resource .desc {
112
- margin: 1em 0;
113
- color:
114
- #333;
115
- display: block;
116
- font-family: Helvetica, sans-serif;
117
- font-size: 13px;
118
- font-style: normal;
119
- font-weight: 100;
120
- height: 17px;
121
- line-height: 17px;
122
- text-shadow:
123
- rgba(255, 255, 255, 0.597656) 0px 1px 0px;
124
- vertical-align: baseline;
125
- }
111
+ .api-resource .desc {
112
+ margin: 1em 0;
113
+ color:
114
+ #333;
115
+ display: block;
116
+ font-family: Helvetica, sans-serif;
117
+ font-size: 13px;
118
+ font-weight: 100;
119
+ height: 17px;
120
+ line-height: 17px;
121
+ text-shadow:
122
+ rgba(255, 255, 255, 0.597656) 0px 1px 0px;
123
+ vertical-align: baseline;
124
+ }
126
125
  .api-resource .params,
127
126
  .api-resource .response {
128
127
  font-family: Monaco, fixed;
@@ -158,17 +157,19 @@
158
157
  <div class="name"></div>
159
158
  <div class="api-resource">
160
159
  <div class="method">GET</div>
161
- <div class="path">/tacos.json</div>
162
- <div class="desc">Get all tacos</div>
160
+ <div class="path">/tacos</div>
161
+ <div class="desc"><p>Get all tacos</p>
162
+ </div>
163
163
  <div class="params"></div>
164
164
  <div class="response">[{&quot;meat&quot;:&quot;chicken&quot;}]</div>
165
165
  </div>
166
166
  <div class="api-resource">
167
167
  <div class="method">POST</div>
168
- <div class="path">/tacos.json</div>
169
- <div class="desc">Make a new delicious taco</div>
170
- <div class="params">{&quot;meat&quot;:&quot;beef&quot;,&quot;lettuce&quot;:true}</div>
171
- <div class="response">{&quot;meat&quot;:&quot;beef&quot;,&quot;lettuce&quot;:true}</div>
168
+ <div class="path">/tacos</div>
169
+ <div class="desc"><p>Make a new delicious taco</p>
170
+ </div>
171
+ <div class="params">{:meat=&gt;&quot;beef&quot;, :lettuce=&gt;true}</div>
172
+ <div class="response">meat=beef&amp;lettuce=true</div>
172
173
  </div>
173
174
 
174
175
  </div>
@@ -5,11 +5,11 @@ require 'sinatra/base'
5
5
 
6
6
  class TacoApp < Sinatra::Base
7
7
 
8
- get '/tacos.json' do
8
+ get '/tacos' do
9
9
  JSON.generate [ { meat: 'chicken' } ]
10
10
  end
11
11
 
12
- post '/tacos.json' do
12
+ post '/tacos' do
13
13
  request.body
14
14
  end
15
15
 
@@ -17,14 +17,14 @@ end
17
17
 
18
18
  doc = ApiDoc.new TacoApp do
19
19
 
20
- get '/tacos.json' do
20
+ get '/tacos' do
21
21
  desc "Get all tacos"
22
22
  end
23
23
 
24
- post '/tacos.json' do
24
+ post '/tacos' do
25
25
  desc "Make a new delicious taco"
26
26
  params do
27
- JSON.generate({ meat: 'beef', lettuce: true })
27
+ { meat: 'beef', lettuce: true }
28
28
  end
29
29
  end
30
30
 
data/ftags CHANGED
@@ -11,13 +11,21 @@ Gemfile.lock ./Gemfile.lock /^/;" r
11
11
  LICENSE.txt ./LICENSE.txt /^/;" r
12
12
  README.rdoc ./README.rdoc /^/;" r
13
13
  Rakefile ./Rakefile /^/;" r
14
+ VERSION ./VERSION /^/;" r
14
15
  apidoc ./bin/apidoc /^/;" r
16
+ apidoc-0.1.2.gem ./pkg/apidoc-0.1.2.gem /^/;" r
17
+ apidoc.gemspec ./apidoc.gemspec /^/;" r
15
18
  apidoc.rb ./lib/apidoc.rb /^/;" r
16
19
  apidoc_helper.rb ./templates/apidoc_helper.rb /^/;" r
17
20
  apidoc_spec.rb ./spec/apidoc_spec.rb /^/;" r
18
21
  authentication.rb ./examples/authentication.rb /^/;" r
22
+ before_and_after_spec.rb ./spec/before_and_after_spec.rb /^/;" r
23
+ burritos_api.html ./examples/burritos_api.html /^/;" r
24
+ burritos_api.rb ./examples/burritos_api.rb /^/;" r
19
25
  config ./.bundle/config /^/;" r
20
26
  ftags ./ftags /^/;" r
21
27
  layout.mustache ./templates/layout.mustache /^/;" r
22
28
  resource.mustache ./templates/resource.mustache /^/;" r
23
29
  spec_helper.rb ./spec/spec_helper.rb /^/;" r
30
+ tacos_api.html ./examples/tacos_api.html /^/;" r
31
+ tacos_api.rb ./examples/tacos_api.rb /^/;" r
@@ -2,6 +2,7 @@ require 'rack/test'
2
2
  require 'thor'
3
3
  require 'mustache'
4
4
  require 'json'
5
+ require 'kramdown'
5
6
 
6
7
  module ApiDoc
7
8
  VERSION = "0.1.0"
@@ -99,6 +100,8 @@ module ApiDoc
99
100
  end
100
101
 
101
102
  def write(stream)
103
+ @runner.run
104
+
102
105
  stream.write(
103
106
  Mustache.to_html(File.read(File.dirname(__FILE__) + '/../templates/layout.mustache'), {
104
107
  content: @runner.resources.map {|r| resource_html(r) }.join
@@ -109,39 +112,15 @@ module ApiDoc
109
112
  end
110
113
 
111
114
  def resource_html(resource)
112
- resource.run
113
-
114
115
  Mustache.to_html(File.read(File.dirname(__FILE__) + '/../templates/resource.mustache'), {
115
116
  method: resource.method,
116
117
  path: resource.path,
117
- desc: resource.desc,
118
- params: formatted_params(resource),
119
- response: formatted_response(resource)
118
+ desc: Kramdown::Document.new(resource.desc).to_html,
119
+ params: resource.formatted_params,
120
+ response: resource.formatted_response
120
121
  })
121
122
  end
122
123
 
123
- def formatted_params(resource)
124
- return '' unless resource.params
125
- return resource.params unless resource.accept
126
-
127
- case resource.accept.intern
128
- when :json
129
- JSON.pretty_generate(JSON.parse(resource.params))
130
- else
131
- resource.params
132
- end
133
- end
134
-
135
- def formatted_response(resource)
136
- return resource.response_body unless resource.content_type
137
-
138
- case resource.content_type.intern
139
- when :json
140
- JSON.pretty_generate(JSON.parse(resource.response_body))
141
- else
142
- resource.response_body
143
- end
144
- end
145
124
  end
146
125
 
147
126
  class Resource
@@ -205,22 +184,60 @@ module ApiDoc
205
184
  def run
206
185
  @before_blocks.each {|block| instance_eval &block }
207
186
  @params = @params.call if @params.is_a?(Proc)
208
- @response = make_request(@path, @params)
187
+ @response = make_request
209
188
  @after_blocks.each {|block| instance_eval &block }
210
189
  end
211
190
 
191
+ def filtered_params
192
+ params.reject {|k, v| path_captures.include?(k) or path_captures.include?(k.to_s)}
193
+ end
194
+
195
+ def formatted_params
196
+ return '' unless params
197
+ return filtered_params unless accept
198
+
199
+ case accept.intern
200
+ when :json
201
+ JSON.pretty_generate(filtered_params)
202
+ else
203
+ filtered_params
204
+ end
205
+ end
206
+
207
+ def formatted_response
208
+ return response_body unless content_type
209
+
210
+ case content_type.intern
211
+ when :json
212
+ JSON.pretty_generate(JSON.parse(response_body))
213
+ else
214
+ response_body
215
+ end
216
+ end
217
+
212
218
  def response_body
213
219
  @response.body
214
220
  end
215
221
 
216
- end
222
+ PATH_CAPTURE_REGEXP = /:[^\.\/]+/
217
223
 
218
- class PostResource < Resource
224
+ def path_captures
225
+ @path.match(PATH_CAPTURE_REGEXP).to_a.map {|m| m.gsub(':', '').intern }
226
+ end
219
227
 
220
- def make_request(path, params)
221
- post path, params
228
+ def interpolated_path
229
+ @path.gsub(PATH_CAPTURE_REGEXP) do |match|
230
+ params[match.gsub(':', '').intern]
231
+ end
232
+ end
233
+
234
+ def make_request
235
+ self.send(@method.downcase.intern, interpolated_path, formatted_params)
222
236
  end
223
237
 
238
+ end
239
+
240
+ class PostResource < Resource
224
241
  def initialize(runner, path, &block)
225
242
  super runner, path, &block
226
243
  @method = 'POST'
@@ -228,11 +245,6 @@ module ApiDoc
228
245
  end
229
246
 
230
247
  class GetResource < Resource
231
-
232
- def make_request(path, params)
233
- get path, params
234
- end
235
-
236
248
  def initialize(runner, path, &block)
237
249
  super runner, path, &block
238
250
  @method = 'GET'
@@ -240,11 +252,6 @@ module ApiDoc
240
252
  end
241
253
 
242
254
  class PutResource < Resource
243
-
244
- def make_request(path, params)
245
- put path, params
246
- end
247
-
248
255
  def initialize(runner, path, &block)
249
256
  super runner, path, &block
250
257
  @method = 'PUT'
@@ -252,11 +259,6 @@ module ApiDoc
252
259
  end
253
260
 
254
261
  class DeleteResource < Resource
255
-
256
- def make_request(path, params)
257
- delete path, params
258
- end
259
-
260
262
  def initialize(runner, path, &block)
261
263
  super runner, path, &block
262
264
  @method = 'DELETE'
@@ -264,11 +266,6 @@ module ApiDoc
264
266
  end
265
267
 
266
268
  class OptionsResource < Resource
267
-
268
- def make_request(path, params)
269
- options path, params
270
- end
271
-
272
269
  def initialize(runner, path, &block)
273
270
  super runner, path, &block
274
271
  @method = 'OPTIONS'