sinatra-doc 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 @@
1
+ .DS_Store
@@ -0,0 +1,41 @@
1
+ # sinatra-doc
2
+
3
+ self documentaion for your [sinatra]("http://sinatrarb.com") app's routes
4
+
5
+ # usage
6
+
7
+ see the reference implementation [app.rb](http://github.com/softprops/sinatra-doc/blob/master/app.rb)
8
+
9
+ > your app.rb
10
+
11
+ class App < Sinatra::Base
12
+ register Sinatra::Doc
13
+
14
+ doc "gets a list of foos"
15
+ get "foos" { ... }
16
+
17
+ doc "gets a specific foo", {
18
+ :id => "identifier for a given foo"
19
+ }
20
+ get "foos/:id" { ... }
21
+ end
22
+
23
+ > GET /doc
24
+
25
+ sinatra doc
26
+
27
+ GET foos gets a list of foos
28
+
29
+ GET foos/:id gets a specific foo
30
+ :id identifier for a given foo
31
+
32
+ # Props
33
+
34
+ based on an idea [@bmizerany]("http://twitter.com/bmizerany") proposed in a [heroku]("http://heroku.com/") talk in nyc
35
+
36
+ # TODO
37
+
38
+ * rake sinatra::doc #=> à la rails rake:routes
39
+ * clean up rendering of docs
40
+
41
+ 2009 softprops (doug tangren)
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/app.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'sinatra/base'
2
+ require File.join(File.dirname(__FILE__), *%w(lib doc))
3
+
4
+ # a reference usage of Sinatra::Doc
5
+ module Kittens
6
+ class App < Sinatra::Base
7
+ register Sinatra::Doc do
8
+ def title
9
+ "kittenz api"
10
+ end
11
+
12
+ def header
13
+ (<<-HEADER)
14
+ <h1>
15
+ <pre>
16
+ kittenz
17
+ _
18
+ \`*-.
19
+ ) _`-.
20
+ . : `. .
21
+ : _ ' \
22
+ ; *` _. `*-._
23
+ `-.-' `-.
24
+ ; ` `.
25
+ :. . \
26
+ . \ . : .-' .
27
+ ' `+.; ; ' :
28
+ : ' | ; ;-.
29
+ ; ' : :`-: _.`* ;
30
+ .*' / .*' ; .*`- +' `*'
31
+ `*-* `*-* `*-*'
32
+ </pre>
33
+ </h1>
34
+ HEADER
35
+ end
36
+ end
37
+
38
+ doc 'lists all kittens'
39
+ get '/kittens' do
40
+ '...'
41
+ end
42
+
43
+ doc 'gets a kitten by name', {
44
+ :name => "name of kitten"
45
+ }
46
+ get '/kittens/:name' do |name|
47
+ "..."
48
+ end
49
+
50
+ doc 'creates a new kitten'
51
+ post '/kittens' do
52
+ '...'
53
+ end
54
+
55
+ doc 'updates a kitten', {
56
+ :name => 'name of kitten'
57
+ }
58
+ put "/kittens/:id" do
59
+ '...'
60
+ end
61
+
62
+ doc 'deletes a given kitten', {
63
+ :name => 'name of kitten'
64
+ }
65
+ delete '/kittens/:name' do |name|
66
+ '...'
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,2 @@
1
+ require 'app'
2
+ run Kittens::App
@@ -0,0 +1,83 @@
1
+ module Sinatra
2
+ # executable api documentation
3
+ module Doc
4
+ class Route
5
+ attr_accessor :desc, :params, :paths
6
+
7
+ def initialize(attrs={})
8
+ attrs.each_pair { |k,v| send "#{k}=",v if respond_to? "#{k}=" }
9
+ self.paths = []
10
+ end
11
+
12
+ def <<(path)
13
+ self.paths << path
14
+ end
15
+
16
+ def to_s
17
+ self.inspect
18
+ end
19
+
20
+ def inspect
21
+ "#{@paths.join(', ')} # #{@desc}"
22
+ end
23
+ end
24
+
25
+ def self.registered(app)
26
+ app.get '/doc' do
27
+ app.instance_eval { render_docs_page(@docs) }
28
+ end
29
+ end
30
+
31
+ def doc(desc, params = {})
32
+ @last_doc = Route.new(:desc => desc, :params => params)
33
+ (@docs ||= []) << @last_doc
34
+ end
35
+
36
+ def title
37
+ "sinatra doc"
38
+ end
39
+
40
+ def header
41
+ "<h1>%s</h1>" % title
42
+ end
43
+
44
+ def method_added(method)
45
+ return if method.to_s =~ /(^(GET|HEAD) \/doc\z)/
46
+ if method.to_s =~ /(GET|POST|PUT|DELETE|UPDATE|HEAD)/ && @last_doc
47
+ @last_doc << method
48
+ @last_doc = nil
49
+ end
50
+ super
51
+ end
52
+
53
+ def render_docs_list(routes)
54
+ routes.inject('<dl>') { |markup, route|
55
+ path = route.paths.join(', ')
56
+ desc = route.desc
57
+ params = route.params.inject('') { |li,(k,v)|
58
+ li << "<dt>:%s</dt><dd>%s</dd>" % [k,v]
59
+ }
60
+ markup << "<dt>%s</dt><dd>%s<dl>%s</dl></dd>" % [path, desc, params]
61
+ } << "</dl>"
62
+ end
63
+
64
+ def render_docs_page(routes)
65
+ (<<-HTML)
66
+ <html>
67
+ <head><title>#{title}</title></head>
68
+ <style type="text/css">
69
+ #container{width:960px; margin:1em auto; font-family:monaco, monospace;}
70
+ dt{ background:#f5f5f5; font-weight:bold; float:left; margin-right:1em; }
71
+ dd{ margin-left:1em; }
72
+ </style>
73
+ <body>
74
+ <div id="container">
75
+ #{header}
76
+ #{render_docs_list(routes)}
77
+ </div>
78
+ </body>
79
+ </html>
80
+ HTML
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), *%w(test_helper))
2
+
3
+ class DocTest < Test::Unit::TestCase
4
+ class A < Sinatra::Base
5
+ register Sinatra::Doc
6
+
7
+ doc "gets a list of materia"
8
+ get "/materia" do
9
+ "..."
10
+ end
11
+
12
+ get "/undocumented" do
13
+ "..."
14
+ end
15
+
16
+ doc "gets a specific materia", {
17
+ :kind => "color of the materia [red,green,blue,yellow,purple]"
18
+ }
19
+ get "/materia/:kind" do
20
+ "..."
21
+ end
22
+ end
23
+
24
+ class B < Sinatra::Base
25
+ register Sinatra::Doc do
26
+ def title
27
+ "Beez Kneez"
28
+ end
29
+ end
30
+
31
+ doc "get a list of bees"
32
+ get "/bees" do
33
+ "..."
34
+ end
35
+ end
36
+
37
+ def documented_app
38
+ A
39
+ end
40
+
41
+ def documented_app_with_overrides
42
+ B
43
+ end
44
+
45
+ context 'a documented sinatra app' do
46
+ should 'have a documented api' do
47
+ browser = Rack::Test::Session.new(
48
+ Rack::MockSession.new(documented_app)
49
+ )
50
+ browser.get '/doc'
51
+ assert browser.last_response.ok?
52
+ [
53
+ "GET /materia",
54
+ "gets a list of materia",
55
+ "/materia/:kind",
56
+ "gets a specific materia",
57
+ "color of the materia [red,green,blue,yellow,purple]"
58
+ ].each { |phrase|
59
+ assert browser.last_response.body.include?(phrase)
60
+ }
61
+
62
+ assert !browser.last_response.body.include?("/undocumented")
63
+ end
64
+
65
+ context "with doc overrides" do
66
+ should "render with overrides" do
67
+ browser = Rack::Test::Session.new(
68
+ Rack::MockSession.new(documented_app_with_overrides)
69
+ )
70
+ browser.get '/doc'
71
+ assert browser.last_response.ok?
72
+ [
73
+ "Beez Kneez",
74
+ "GET /bees",
75
+ "get a list of bees"
76
+ ].each { |phrase|
77
+ assert browser.last_response.body.include?(phrase)
78
+ }
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), *%w(.. app))
2
+ require 'shoulda'
3
+ require 'rack/test'
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-doc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Doug Tangren
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-04 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: self documentaion for your sinatra app's routes
17
+ email: d.tangren@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.md
24
+ files:
25
+ - .gitignore
26
+ - README.md
27
+ - VERSION
28
+ - app.rb
29
+ - config.ru
30
+ - lib/doc.rb
31
+ - test/doc_test.rb
32
+ - test/test_helper.rb
33
+ has_rdoc: true
34
+ homepage: http://github.com/softprops/sinatra-doc
35
+ licenses: []
36
+
37
+ post_install_message:
38
+ rdoc_options:
39
+ - --charset=UTF-8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ version:
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ requirements: []
55
+
56
+ rubyforge_project:
57
+ rubygems_version: 1.3.5
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: self documentaion for your sinatra app's routes
61
+ test_files:
62
+ - test/doc_test.rb
63
+ - test/test_helper.rb