apidoc 0.1.0

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.
@@ -0,0 +1,37 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'apidoc'
4
+ require 'sinatra/base'
5
+
6
+ class BurritoApp < Sinatra::Base
7
+
8
+ get '/burritos.json' do
9
+ JSON.generate [ { meat: 'chicken' }, { meat: 'tofu' } ]
10
+ end
11
+
12
+ post '/burritos.json' do
13
+ request.body
14
+ end
15
+
16
+ end
17
+
18
+ doc = ApiDoc.new BurritoApp do
19
+
20
+ accept :json
21
+ content_type :json
22
+
23
+ get '/burritos.json' do
24
+ desc "Get all burritos"
25
+ end
26
+
27
+ post '/burritos.json' do
28
+ desc "Make a new delicious burrito"
29
+ params do
30
+ JSON.generate({ meat: 'beef', lettuce: true })
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ ApiDoc::HtmlWriter.new(doc).write(STDOUT)
37
+
@@ -0,0 +1,177 @@
1
+ <html>
2
+ <head>
3
+ <title></title>
4
+ <style>
5
+
6
+ html, body, div, span, applet, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ a, abbr, acronym, address, big, cite, code,
9
+ del, dfn, em, img, ins, kbd, q, s, samp,
10
+ small, strike, strong, sub, sup, tt, var,
11
+ b, u, i, center,
12
+ dl, dt, dd, ol, ul, li,
13
+ fieldset, form, label, legend,
14
+ table, caption, tbody, tfoot, thead, tr, th, td,
15
+ article, aside, canvas, details, embed,
16
+ figure, figcaption, footer, header, hgroup,
17
+ menu, nav, output, ruby, section, summary,
18
+ time, mark, audio, video {
19
+ margin: 0;
20
+ padding: 0;
21
+ border: 0;
22
+ font-size: 100%;
23
+ font: inherit;
24
+ vertical-align: baseline;
25
+ }
26
+ /* HTML5 display-role reset for older browsers */
27
+ article, aside, details, figcaption, figure,
28
+ footer, header, hgroup, menu, nav, section {
29
+ display: block;
30
+ }
31
+ body {
32
+ line-height: 1;
33
+ }
34
+ ol, ul {
35
+ list-style: none;
36
+ }
37
+ blockquote, q {
38
+ quotes: none;
39
+ }
40
+ blockquote:before, blockquote:after,
41
+ q:before, q:after {
42
+ content: '';
43
+ content: none;
44
+ }
45
+ table {
46
+ border-collapse: collapse;
47
+ border-spacing: 0;
48
+ }
49
+
50
+
51
+
52
+
53
+
54
+ body {
55
+ font-family: Helvetica;
56
+ margin: 1em;
57
+ }
58
+
59
+ .name {
60
+ font-size: 2.0em;
61
+ }
62
+
63
+ .api-resource {
64
+ margin: 1em 0;
65
+ }
66
+
67
+ .api-resource .method {
68
+ font-size: 1em;
69
+ background-color: #999;
70
+ background-image: -webkit-linear-gradient(top,
71
+ transparent 0%,
72
+ rgba(0, 0, 0, 0.296875) 100%);
73
+ background-origin: padding-box;
74
+ border-bottom-color:
75
+ white;
76
+ border-bottom-left-radius: 0px;
77
+ border-bottom-style: none;
78
+ border-bottom-width: 0px;
79
+ border-left-color:
80
+ white;
81
+ border-left-style: none;
82
+ border-left-width: 0px;
83
+ border-right-color:
84
+ white;
85
+ border-right-style: none;
86
+ border-right-width: 0px;
87
+ border-top-color:
88
+ white;
89
+ border-top-left-radius: 3px;
90
+ border-top-style: none;
91
+ border-top-width: 0px;
92
+ color:
93
+ white;
94
+ text-align: center;
95
+ text-shadow:
96
+ rgba(0, 0, 0, 0.296875) 0px -1px 0px;
97
+ text-transform: uppercase;
98
+ vertical-align: baseline;
99
+ padding: 0.5em;
100
+ display: inline-block;
101
+ width: 84px;
102
+ }
103
+
104
+ .api-resource .path {
105
+ display: inline-block;
106
+ font-family: Monaco, fixed;
107
+ color: #0669CD;
108
+ font-size: 1em;
109
+ }
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
+ }
126
+ .api-resource .params,
127
+ .api-resource .response {
128
+ font-family: Monaco, fixed;
129
+ margin: 1em 0;
130
+ overflow: scroll;
131
+ white-space: pre;
132
+ background-color: #333333;
133
+ color: #8B8B8B;
134
+ padding: 1em;
135
+ border-radius: 2px;
136
+ }
137
+
138
+ .api-resource .params:before {
139
+ content: "IN";
140
+ color: #C29262;
141
+ display: block;
142
+ font-family: Helvetica;
143
+ margin: 0.5em 0;
144
+ }
145
+
146
+ .api-resource .response:before {
147
+ content: "OUT";
148
+ display: block;
149
+ color: #C29262;
150
+ font-family: Helvetica;
151
+ margin: 0.5em 0;
152
+ }
153
+ </style>
154
+ </head>
155
+
156
+ <body>
157
+ <div class="api">
158
+ <div class="name"></div>
159
+ <div class="api-resource">
160
+ <div class="method">GET</div>
161
+ <div class="path">/tacos.json</div>
162
+ <div class="desc">Get all tacos</div>
163
+ <div class="params"></div>
164
+ <div class="response">[{&quot;meat&quot;:&quot;chicken&quot;}]</div>
165
+ </div>
166
+ <div class="api-resource">
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>
172
+ </div>
173
+
174
+ </div>
175
+ </body>
176
+ </html>
177
+
@@ -0,0 +1,34 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'apidoc'
4
+ require 'sinatra/base'
5
+
6
+ class TacoApp < Sinatra::Base
7
+
8
+ get '/tacos.json' do
9
+ JSON.generate [ { meat: 'chicken' } ]
10
+ end
11
+
12
+ post '/tacos.json' do
13
+ request.body
14
+ end
15
+
16
+ end
17
+
18
+ doc = ApiDoc.new TacoApp do
19
+
20
+ get '/tacos.json' do
21
+ desc "Get all tacos"
22
+ end
23
+
24
+ post '/tacos.json' do
25
+ desc "Make a new delicious taco"
26
+ params do
27
+ JSON.generate({ meat: 'beef', lettuce: true })
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ ApiDoc::HtmlWriter.new(doc).write(STDOUT)
34
+
data/ftags ADDED
@@ -0,0 +1,23 @@
1
+ !_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
2
+ !_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
3
+ !_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
4
+ !_TAG_PROGRAM_NAME Exuberant Ctags //
5
+ !_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
6
+ !_TAG_PROGRAM_VERSION 5.7 //
7
+ .document ./.document /^/;" r
8
+ .rspec ./.rspec /^/;" r
9
+ Gemfile ./Gemfile /^/;" r
10
+ Gemfile.lock ./Gemfile.lock /^/;" r
11
+ LICENSE.txt ./LICENSE.txt /^/;" r
12
+ README.rdoc ./README.rdoc /^/;" r
13
+ Rakefile ./Rakefile /^/;" r
14
+ apidoc ./bin/apidoc /^/;" r
15
+ apidoc.rb ./lib/apidoc.rb /^/;" r
16
+ apidoc_helper.rb ./templates/apidoc_helper.rb /^/;" r
17
+ apidoc_spec.rb ./spec/apidoc_spec.rb /^/;" r
18
+ authentication.rb ./examples/authentication.rb /^/;" r
19
+ config ./.bundle/config /^/;" r
20
+ ftags ./ftags /^/;" r
21
+ layout.mustache ./templates/layout.mustache /^/;" r
22
+ resource.mustache ./templates/resource.mustache /^/;" r
23
+ spec_helper.rb ./spec/spec_helper.rb /^/;" r
@@ -0,0 +1,255 @@
1
+ require 'rack/test'
2
+ require 'thor'
3
+ require 'mustache'
4
+ require 'json'
5
+
6
+ module ApiDoc
7
+ VERSION = "0.1.0"
8
+
9
+ class << self
10
+ def new(app, &block)
11
+ @app = app
12
+ Runner.new(&block)
13
+ end
14
+
15
+ def app; @app; end
16
+ end
17
+
18
+ class Runner
19
+ def initialize(&block)
20
+ @resources = []
21
+ @accept = nil
22
+ @content_type = nil
23
+ Blueprint.new self, &block
24
+ end
25
+
26
+ attr_accessor :resources, :accept, :content_type
27
+
28
+ class Blueprint
29
+ def initialize(runner, &block)
30
+ @runner = runner
31
+ instance_eval &block
32
+ end
33
+
34
+ def accept(type)
35
+ @runner.accept = type
36
+ end
37
+
38
+ def content_type(type)
39
+ @runner.content_type = type
40
+ end
41
+
42
+ def get(path, &block)
43
+ @runner.resources << GetResource.new(@runner, path, &block)
44
+ end
45
+
46
+ def post(path, &block)
47
+ @runner.resources << PostResource.new(@runner, path, &block)
48
+ end
49
+
50
+ def put(path, &block)
51
+ @runner.resources << PutResource.new(@runner, path, &block)
52
+ end
53
+
54
+ def delete(path, &block)
55
+ @runner.resources << DeleteResource.new(@runner, path, &block)
56
+ end
57
+
58
+ def options(path, &block)
59
+ @runner.resources << OptionsResource.new(@runner, path, &block)
60
+ end
61
+ end
62
+
63
+ def run
64
+ @resources.each(&:run)
65
+ end
66
+ end
67
+
68
+ class HtmlWriter
69
+ def initialize(runner)
70
+ @runner = runner
71
+ end
72
+
73
+ def write(stream)
74
+ stream.write(
75
+ Mustache.to_html(File.read(File.dirname(__FILE__) + '/../templates/layout.mustache'), {
76
+ content: @runner.resources.map {|r| resource_html(r) }.join
77
+ })
78
+ )
79
+ stream.rewind
80
+ stream
81
+ end
82
+
83
+ def resource_html(resource)
84
+ resource.run
85
+
86
+ Mustache.to_html(File.read(File.dirname(__FILE__) + '/../templates/resource.mustache'), {
87
+ method: resource.method,
88
+ path: resource.path,
89
+ desc: resource.desc,
90
+ params: formatted_params(resource),
91
+ response: formatted_response(resource)
92
+ })
93
+ end
94
+
95
+ def formatted_params(resource)
96
+ return '' unless resource.params
97
+ return resource.params unless resource.accept
98
+
99
+ case resource.accept.intern
100
+ when :json
101
+ JSON.pretty_generate(JSON.parse(resource.params))
102
+ else
103
+ resource.params
104
+ end
105
+ end
106
+
107
+ def formatted_response(resource)
108
+ return resource.response_body unless resource.content_type
109
+
110
+ case resource.content_type.intern
111
+ when :json
112
+ JSON.pretty_generate(JSON.parse(resource.response_body))
113
+ else
114
+ resource.response_body
115
+ end
116
+ end
117
+ end
118
+
119
+ class Resource
120
+ def initialize(runner, path, &block)
121
+ @runner = runner
122
+ @path = path
123
+ @params = nil
124
+ Blueprint.new self, &block
125
+ end
126
+
127
+ attr_accessor :path, :method, :setup, :params, :desc
128
+ attr_writer :accept, :content_type
129
+
130
+ class Blueprint
131
+ def initialize(resource, &block)
132
+ @resource = resource
133
+ instance_eval &block
134
+ end
135
+
136
+ def desc(val)
137
+ @resource.desc = val
138
+ end
139
+
140
+ def accept(format)
141
+ @resource.accept = format
142
+ end
143
+
144
+ def content_type(format)
145
+ @resource.content_type = format
146
+ end
147
+
148
+ def params(&block)
149
+ @resource.params = block
150
+ end
151
+
152
+ def setup(&block)
153
+ @resource.setup = block
154
+ end
155
+ end
156
+
157
+ include Rack::Test::Methods
158
+
159
+ def content_type
160
+ @content_type || @runner.content_type
161
+ end
162
+
163
+ def accept
164
+ @accept || @runner.accept
165
+ end
166
+
167
+ def app
168
+ ApiDoc.app
169
+ end
170
+
171
+ def run
172
+ if @setup
173
+ instance_eval &@setup
174
+ end
175
+ @params = @params.call if @params.is_a?(Proc)
176
+ @response = make_request(@path, @params)
177
+ end
178
+
179
+ def response_body
180
+ @response.body
181
+ end
182
+
183
+ end
184
+
185
+ class PostResource < Resource
186
+
187
+ def make_request(path, params)
188
+ post path, params
189
+ end
190
+
191
+ def initialize(runner, path, &block)
192
+ super runner, path, &block
193
+ @method = 'POST'
194
+ end
195
+ end
196
+
197
+ class GetResource < Resource
198
+
199
+ def make_request(path, params)
200
+ get path, params
201
+ end
202
+
203
+ def initialize(runner, path, &block)
204
+ super runner, path, &block
205
+ @method = 'GET'
206
+ end
207
+ end
208
+
209
+ class PutResource < Resource
210
+
211
+ def make_request(path, params)
212
+ put path, params
213
+ end
214
+
215
+ def initialize(runner, path, &block)
216
+ super runner, path, &block
217
+ @method = 'PUT'
218
+ end
219
+ end
220
+
221
+ class DeleteResource < Resource
222
+
223
+ def make_request(path, params)
224
+ delete path, params
225
+ end
226
+
227
+ def initialize(runner, path, &block)
228
+ super runner, path, &block
229
+ @method = 'DELETE'
230
+ end
231
+ end
232
+
233
+ class OptionsResource < Resource
234
+
235
+ def make_request(path, params)
236
+ options path, params
237
+ end
238
+
239
+ def initialize(runner, path, &block)
240
+ super runner, path, &block
241
+ @method = 'OPTIONS'
242
+ end
243
+ end
244
+
245
+ class Application < Thor
246
+ map '-v' => :version
247
+
248
+ desc "version", "print version information"
249
+ def version
250
+ puts ApiDoc::VERSION
251
+ end
252
+ end
253
+
254
+ end
255
+