apidoc 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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'