rdoc-sinatra 1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
File without changes
@@ -0,0 +1,12 @@
1
+ *.rbc
2
+ doc/
3
+ /doc
4
+ pkg/
5
+ /pkg
6
+ coverage/
7
+ .yardoc/
8
+ /tags
9
+ TAGS
10
+ *.gem
11
+ .bundle
12
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in rdoc-sinatra.gemspec
4
+ gemspec
@@ -0,0 +1,83 @@
1
+ rdoc-sinatra
2
+ ============
3
+
4
+ RDoc plugin for documenting Sinatra applications.
5
+
6
+
7
+ Homepage and Bugtracker
8
+ -----------------------
9
+
10
+ https://github.com/rdoc/rdoc-sinatra
11
+
12
+
13
+ Requirements
14
+ ------------
15
+
16
+ - rdoc 3+
17
+
18
+
19
+ Installation
20
+ ------------
21
+
22
+ `$ gem install rdoc-rake`
23
+
24
+
25
+ Usage
26
+ -----
27
+
28
+ `$ rdoc FILE_OR_DIR […]`
29
+
30
+ The plugin extracts documentation for route definitions marked with
31
+ a double-hash (that bit is important):
32
+
33
+ ##
34
+ # This is your documentation.
35
+ #
36
+ # And then some.
37
+ #
38
+ get "/foo" do
39
+ :yay
40
+ end
41
+
42
+ This plugin augments the normal RDoc Ruby parser, so that you can
43
+ generate the documentation along with the rest of your methods.
44
+
45
+ The route docs are placed under a fake class called Application Routes.
46
+
47
+
48
+ Limitations/TODO
49
+ ----------------
50
+
51
+ - Currently all routes are parsed into the top-level Application Routes.
52
+ This'll probably change in the next version.
53
+ - Does not actually parse the route patterns, so parameters and so
54
+ on aren't documented separately (you'll just see the entire pattern).
55
+
56
+
57
+
58
+ Licence
59
+ -------
60
+
61
+ (The MIT License)
62
+
63
+ Copyright (c) 2011 Eero Saynatkari
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
83
+
@@ -0,0 +1,14 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "rubygems"
4
+ require "bundler/gem_tasks"
5
+
6
+ require "rake/testtask"
7
+
8
+
9
+ Rake::TestTask.new do |t|
10
+ t.libs.push "lib"
11
+ t.test_files = FileList["test/test_*.rb"]
12
+ t.verbose = true
13
+ end
14
+
@@ -0,0 +1,7 @@
1
+ begin
2
+ gem "rdoc", "~> 3"
3
+ require "rdoc/parser/sinatra"
4
+
5
+ rescue Gem::LoadError
6
+ # Meh
7
+ end
@@ -0,0 +1,145 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "rdoc"
4
+ require "rdoc/parser/ruby"
5
+
6
+
7
+ #
8
+ # Artificial scope for top-level routes.
9
+ #
10
+ class RDoc::SinatraRoutes < RDoc::AnonClass
11
+ end
12
+
13
+ #
14
+ # Sinatra route definition as a method.
15
+ #
16
+ class RDoc::SinatraRoute < RDoc::AnyMethod
17
+
18
+ def initialize(route_definition, content_text)
19
+ super(content_text, route_definition)
20
+
21
+ @params = ""
22
+ end
23
+
24
+ def aref_prefix
25
+ ""
26
+ end
27
+ end
28
+
29
+ #
30
+ # Sinatra routing error definition as a method.
31
+ #
32
+ class RDoc::SinatraRouteError < RDoc::SinatraRoute
33
+ end
34
+
35
+
36
+ #
37
+ # An augmented Ruby parser for Sinatra projects.
38
+ #
39
+ # In addition to normal Ruby doc, documentation is also extracted
40
+ # for route definitions.
41
+ #
42
+ class RDoc::Parser::Sinatra < RDoc::Parser::Ruby
43
+
44
+ # Re-declare to force overriding the normal .rb handler.
45
+ parse_files_matching /\.rbw?$/i
46
+
47
+
48
+ HTTP_VERBS = %w[GET HEAD POST PUT PATCH DELETE OPTIONS]
49
+ HTTP_ERRORS = {"NOT_FOUND" => 404, "ERROR" => 500}
50
+
51
+
52
+ #
53
+ # New parser, adds a top-level Application Routes.
54
+ #
55
+ def initialize(top_level, file_name, content, options, stats)
56
+ super
57
+
58
+ # Tuck away our little special module
59
+ @routes = @top_level.add_module RDoc::SinatraRoutes, "Application Routes"
60
+
61
+ @current_route = nil
62
+ end
63
+
64
+ #
65
+ # Override normal meta-method parsing to handle Sinatra routes and errors.
66
+ #
67
+ def parse_meta_method(container, single, token, comment)
68
+ name = token.name.upcase
69
+
70
+ case name
71
+ when *HTTP_VERBS
72
+ r = parse_route_definition token
73
+ r.comment = comment
74
+ when "NOT_FOUND", "ERROR"
75
+ r = parse_error_definition token
76
+ r.comment = comment
77
+ else
78
+ super
79
+ end
80
+ end
81
+
82
+
83
+ private
84
+
85
+ def parse_route_definition(http_method_token)
86
+ start_collecting_tokens
87
+ add_token http_method_token
88
+
89
+ token_listener(self) {
90
+ skip_tkspace false
91
+
92
+ pattern_token = get_tk
93
+ route_pattern = pattern_token.text
94
+
95
+ route_name = "#{http_method_token.name.upcase} #{route_pattern}"
96
+
97
+ if r = @routes.find_instance_method_named(route_name)
98
+ warn "Redefining route #{route_name}"
99
+ @current_route = r
100
+ else
101
+ @current_route = RDoc::SinatraRoute.new route_name, tokens_to_s
102
+ @routes.add_method @current_route
103
+ @stats.add_method @current_route
104
+ end
105
+ }
106
+
107
+ @current_route
108
+ end
109
+
110
+ def parse_error_definition(error_token)
111
+ start_collecting_tokens
112
+ add_token error_token
113
+
114
+ token_listener(self) {
115
+ skip_tkspace false
116
+
117
+ pattern_token = get_tk
118
+
119
+ status_codes = if TkDO === pattern_token
120
+ HTTP_ERRORS["ERROR"]
121
+ else
122
+ pattern_token.text
123
+ end
124
+
125
+ if error_token.name == "not_found"
126
+ route_name = "error #{HTTP_ERRORS["NOT_FOUND"]}"
127
+ else
128
+ route_name = "error #{status_codes}"
129
+ end
130
+
131
+ if r = @routes.find_instance_method_named(route_name)
132
+ warn "Redefining error #{error_token.name} #{pattern_token}"
133
+ @current_route = r
134
+ else
135
+ @current_route = RDoc::SinatraRouteError.new route_name, tokens_to_s
136
+ @routes.add_method @current_route
137
+ @stats.add_method @current_route
138
+ end
139
+ }
140
+
141
+ @current_route
142
+ end
143
+
144
+
145
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "rdoc-sinatra"
5
+ s.version = `git tag -l | wc -l`.chomp.to_i
6
+
7
+ s.platform = Gem::Platform::RUBY
8
+
9
+ s.authors = ["Eero Saynatkari"]
10
+ s.email = ["projects@kittensoft.org"]
11
+ s.homepage = "http://github.com/rdoc/rdoc-sinatra"
12
+
13
+ s.summary = %q{RDoc for Sinatra routes.}
14
+ s.description = %q{RDoc plugin for extracting documentation for your Sinatra app's routes.}
15
+
16
+ s.files = `git ls-files`.split "\n"
17
+ s.test_files = `git ls-files -- test/*`.split "\n"
18
+
19
+ s.require_paths = %w{lib}
20
+
21
+ s.add_runtime_dependency "rdoc", "~> 3.0"
22
+
23
+ s.add_development_dependency "minitest"
24
+ end
25
+
@@ -0,0 +1,416 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "stringio"
4
+ require "tempfile"
5
+
6
+ require "rdoc"
7
+ require "rdoc/parser/sinatra"
8
+
9
+ require "minitest/autorun"
10
+
11
+
12
+ class TestRDocParserSinatra < MiniTest::Unit::TestCase
13
+
14
+ def setup
15
+ @tempfile = Tempfile.new self.class.name
16
+ @filename = @tempfile.path
17
+
18
+ RDoc::TopLevel.reset
19
+ @top_level = RDoc::TopLevel.new @filename
20
+
21
+ @options = RDoc::Options.new
22
+ @options.quiet = true
23
+ @stats = RDoc::Stats.new 0
24
+
25
+ @route_definitions = @routes = nil
26
+ end
27
+
28
+ def teardown
29
+ @tempfile.close
30
+ end
31
+
32
+
33
+
34
+ def test_routes_stored_in_top_level_application_routes_class_hiding_in_modules
35
+ app = <<-APP
36
+ require "sinatra"
37
+
38
+ ##
39
+ # Route 1
40
+ #
41
+ get "/foo" do
42
+ :hi
43
+ end
44
+ APP
45
+
46
+ make_a_parser_for app
47
+ @parser.scan
48
+
49
+ r = RDoc::TopLevel.find_module_named "Application Routes"
50
+ r.wont_be_nil
51
+
52
+ r.method_list.first.name.must_equal 'GET "/foo"'
53
+ end
54
+
55
+ def test_route_presented_as_http_method_and_route_pattern
56
+ app = <<-APP
57
+ require "sinatra"
58
+
59
+ ##
60
+ # Route 2
61
+ #
62
+ # Some more text goes here.
63
+ #
64
+ get "/foo" do
65
+ :hi
66
+ end
67
+ APP
68
+
69
+ make_a_parser_for app
70
+ extract_routes
71
+
72
+ r = @routes.first
73
+
74
+ r.name.must_equal 'GET "/foo"'
75
+ r.comment.text.must_equal "Route 2\n\nSome more text goes here."
76
+ end
77
+
78
+ def test_route_pattern_may_be_regexp
79
+ app = <<-APP
80
+ require "sinatra"
81
+
82
+ ##
83
+ # Route 3
84
+ #
85
+ get /foo/ do
86
+ :hi
87
+ end
88
+
89
+ ##
90
+ # Route 4
91
+ #
92
+ get %r{bar} do
93
+ :ho
94
+ end
95
+ APP
96
+
97
+ make_a_parser_for app
98
+ extract_routes
99
+
100
+ @routes.size.must_equal 2
101
+
102
+ r = @routes.first
103
+ r.name.must_equal 'GET /foo/'
104
+ r.comment.text.must_equal "Route 3"
105
+
106
+ r = @routes.last
107
+ r.name.must_equal 'GET %r{bar}'
108
+ r.comment.text.must_equal "Route 4"
109
+ end
110
+
111
+
112
+ %w[GET HEAD POST PUT PATCH DELETE OPTIONS].each {|http|
113
+ define_method("test_parses_#{http}_definition") {
114
+ make_a_parser_for define_all_the_things!
115
+ extract_routes
116
+
117
+ @routes.find {|r| r.name.include? http }.wont_be_nil
118
+ }
119
+ }
120
+
121
+ def test_parses_error_definitions_without_status_code_defaulting_to_500
122
+ app = <<-APP
123
+ require "sinatra"
124
+
125
+ ##
126
+ # Gettersy
127
+ #
128
+ get "foo" do
129
+ :hi
130
+ end
131
+
132
+ ##
133
+ # OMG ERROR
134
+ #
135
+ error do
136
+ :haha
137
+ end
138
+ APP
139
+
140
+ make_a_parser_for app
141
+ extract_routes
142
+
143
+ @routes.size.must_equal 2
144
+
145
+ r = @routes.last
146
+ r.name.must_equal "error 500"
147
+ end
148
+
149
+ def test_parses_error_definitions_with_status_codes
150
+ app = <<-APP
151
+ require "sinatra"
152
+
153
+ ##
154
+ # Getters
155
+ #
156
+ get "foo" do
157
+ :hi
158
+ end
159
+
160
+ ##
161
+ # Fourohthree
162
+ #
163
+ error 403 do
164
+ :haha
165
+ end
166
+ APP
167
+
168
+ make_a_parser_for app
169
+ extract_routes
170
+
171
+ @routes.size.must_equal 2
172
+
173
+ r = @routes.last
174
+ r.name.must_equal "error 403"
175
+ end
176
+
177
+ def test_parses_not_found_definition_into_a_404_error
178
+ app = <<-APP
179
+ require "sinatra"
180
+
181
+ ##
182
+ # Route 5
183
+ #
184
+ get "foo" do
185
+ :hi
186
+ end
187
+
188
+ ##
189
+ # Route 6
190
+ #
191
+ not_found do
192
+ :haha
193
+ end
194
+ APP
195
+
196
+ make_a_parser_for app
197
+ extract_routes
198
+
199
+ @routes.size.must_equal 2
200
+
201
+ r = @routes.last
202
+ r.name.must_equal "error 404"
203
+ end
204
+
205
+ def test_parses_same_route_pattern_with_different_methods_as_separate
206
+ app = <<-APP
207
+ require "sinatra"
208
+
209
+ ##
210
+ # Route 7
211
+ #
212
+ get "foo" do
213
+ :hi
214
+ end
215
+
216
+ ##
217
+ # Route 8
218
+ #
219
+ put "foo" do
220
+ :ho
221
+ end
222
+ APP
223
+
224
+ make_a_parser_for app
225
+ extract_routes
226
+
227
+ @routes.size.must_equal 2
228
+
229
+ r = @routes.first
230
+ r.name.must_equal 'GET "foo"'
231
+
232
+ r = @routes.last
233
+ r.name.must_equal 'PUT "foo"'
234
+ end
235
+
236
+ def test_parses_same_route_pattern_with_same_method_as_the_same_and_latter_overrides
237
+ app = <<-APP
238
+ require "sinatra"
239
+
240
+ ##
241
+ # Initial definition
242
+ #
243
+ get "foo" do
244
+ :hi
245
+ end
246
+
247
+ ##
248
+ # YAY OVERRIDE
249
+ #
250
+ get "foo" do
251
+ :ho
252
+ end
253
+ APP
254
+
255
+ make_a_parser_for app
256
+ extract_routes
257
+
258
+ @routes.size.must_equal 1
259
+
260
+ r = @routes.first
261
+ r.name.must_equal 'GET "foo"'
262
+ r.comment.text.must_equal "YAY OVERRIDE"
263
+ end
264
+
265
+ # May end up not doing this at all.
266
+ # def test_get_definitions_automatically_add_a_head_definition_with_same_comment
267
+ # flunk
268
+ # end
269
+
270
+ def test_allows_normal_ruby_docs_to_be_mixed_in_same_doc
271
+ app = <<-APP
272
+ require "sinatra"
273
+
274
+ ##
275
+ # Route def
276
+ #
277
+ get "foo" do
278
+ :hi
279
+ end
280
+
281
+ #
282
+ # Random method
283
+ #
284
+ def foo; end
285
+
286
+ #
287
+ # Random class
288
+ #
289
+ class Yay
290
+
291
+ ##
292
+ # Random metamethod
293
+ #
294
+ some_meta :metafoo
295
+
296
+ #
297
+ # Random method in a class
298
+ #
299
+ def yayfoo; end
300
+ end
301
+ APP
302
+
303
+ make_a_parser_for app
304
+ extract_routes
305
+
306
+ @routes.size.must_equal 1
307
+
308
+ o = RDoc::TopLevel.find_class_named "Object"
309
+ o.method_list.first.name.must_equal "foo"
310
+
311
+ y = RDoc::TopLevel.find_class_named "Yay"
312
+ y.method_list.size.must_equal 2
313
+
314
+ y.method_list.shift.name.must_equal "metafoo"
315
+ y.method_list.shift.name.must_equal "yayfoo"
316
+ end
317
+
318
+ def test_parses_route_inside_a_class_definition
319
+ app = <<-APP
320
+ require "sinatra"
321
+
322
+ class Yay < Sinatra::Base
323
+ ##
324
+ # Route 9
325
+ #
326
+ get "foo" do
327
+ :hi
328
+ end
329
+ end
330
+ APP
331
+
332
+ make_a_parser_for app
333
+ extract_routes
334
+
335
+ @routes.size.must_equal 1
336
+
337
+ r = @routes.first
338
+ r.name.must_equal 'GET "foo"'
339
+ end
340
+
341
+ # def test_parses_route_inside_a_sinatra_base_inheriting_class_only
342
+ # flunk
343
+ # end
344
+ #
345
+ # def test_parses_route_inside_a_base_class_into_that_class_not_application_routes
346
+ # flunk
347
+ # end
348
+
349
+
350
+ private
351
+
352
+ def make_a_parser_for(content)
353
+ @parser = RDoc::Parser::Sinatra.new @top_level, @filename, content, @options, @stats
354
+ end
355
+
356
+ def extract_routes
357
+ @parser.scan
358
+ @route_definitions = RDoc::TopLevel.find_module_named "Application Routes"
359
+ @routes = @route_definitions.method_list
360
+ end
361
+
362
+ def define_all_the_things!
363
+ <<-END
364
+ require "sinatra"
365
+
366
+ ##
367
+ # GET route
368
+ #
369
+ get "/foo" do
370
+ "hi"
371
+ end
372
+
373
+ ##
374
+ # HEAD route
375
+ #
376
+ head "/bar" do
377
+ "ho"
378
+ end
379
+
380
+ ##
381
+ # POST route
382
+ #
383
+ post "/foo/:id" do
384
+ :yay
385
+ end
386
+
387
+ ##
388
+ # PUT route
389
+ #
390
+ put "/foo/:id" do
391
+ :yay
392
+ end
393
+
394
+ ##
395
+ # DELETE route
396
+ #
397
+ delete %r{hi there} do
398
+ :ugg
399
+ end
400
+
401
+ ##
402
+ # PATCH route
403
+ #
404
+ patch /foo^bar/ do
405
+ :mug
406
+ end
407
+
408
+ ##
409
+ # OPTIONS route
410
+ #
411
+ options "foo/" do
412
+ :whatevs
413
+ end
414
+ END
415
+ end
416
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdoc-sinatra
3
+ version: !ruby/object:Gem::Version
4
+ version: '1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Eero Saynatkari
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: &70238704092380 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70238704092380
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &70238704091140 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70238704091140
36
+ description: RDoc plugin for extracting documentation for your Sinatra app's routes.
37
+ email:
38
+ - projects@kittensoft.org
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .autotest
44
+ - .gemtest
45
+ - .gitignore
46
+ - Gemfile
47
+ - README.md
48
+ - Rakefile
49
+ - lib/rdoc/discover.rb
50
+ - lib/rdoc/parser/sinatra.rb
51
+ - rdoc-sinatra.gemspec
52
+ - test/test_rdoc_parser_sinatra.rb
53
+ homepage: http://github.com/rdoc/rdoc-sinatra
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.10
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: RDoc for Sinatra routes.
77
+ test_files:
78
+ - test/test_rdoc_parser_sinatra.rb