sinatra-croon 0.0.1

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/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Sinatra::Croon
2
+
3
+ Allows you to add inline documentation to a Sinatra app and have a web-based
4
+ documentation browser be available to you.
5
+
6
+ ## Usage
7
+
8
+ require "sinatra/croon"
9
+
10
+ class MyApp < Sinatra::Base
11
+ register Sinatra::Croon
12
+ end
13
+
14
+ ## Documentation Format
15
+
16
+ # Create an application.
17
+ #
18
+ # @param <name> the name of the application to create
19
+ # @param [stack] the stack on which to create the application
20
+ #
21
+ # @request
22
+ # POST /apps.json
23
+ # name=example&stack=bamboo-ree-1.8.7
24
+ # @response
25
+ # {
26
+ # "id": 1,
27
+ # "name": "example",
28
+ # "owner": "user@example.org",
29
+ # "created_at": "Sat Jan 01 00:00:00 UTC 2000",
30
+ # "stack": "bamboo-ree-1.8.7",
31
+ # "slug_size": 1000000,
32
+ # "repo_size": 500000,
33
+ # "dynos": 1,
34
+ # "workers": 0
35
+ # }
36
+
37
+ post "/apps.json" do
38
+ # do something here
39
+ end
40
+
41
+ ## Web-based browser
42
+
43
+ Sinatra::Croon will create a route at `/docs` to display your documentation.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "rspec"
4
+ require "rspec/core/rake_task"
5
+
6
+ $:.unshift File.expand_path("../lib", __FILE__)
7
+ require "sinatra/croon"
8
+
9
+ task :default => :spec
10
+
11
+ desc "Run all specs"
12
+ Rspec::Core::RakeTask.new(:spec) do |t|
13
+ t.pattern = 'spec/**/*_spec.rb'
14
+ end
15
+
16
+ desc "Generate RCov code coverage report"
17
+ task :rcov => "rcov:build" do
18
+ %x{ open coverage/index.html }
19
+ end
20
+
21
+ Rspec::Core::RakeTask.new("rcov:build") do |t|
22
+ t.pattern = 'spec/**/*_spec.rb'
23
+ t.rcov = true
24
+ t.rcov_opts = [ "--exclude", Gem.default_dir, "--exclude", "spec" ]
25
+ end
26
+
27
+ ######################################################
28
+
29
+ begin
30
+ require 'jeweler'
31
+ Jeweler::Tasks.new do |s|
32
+ s.name = "sinatra-croon"
33
+ s.version = Sinatra::Croon::VERSION
34
+
35
+ s.summary = "Create documentation for an API built in Sinatra."
36
+ s.description = s.summary
37
+ s.author = "David Dollar"
38
+ s.email = "ddollar@gmail.com"
39
+ s.homepage = "http://daviddollar.org/"
40
+
41
+ s.platform = Gem::Platform::RUBY
42
+ s.has_rdoc = false
43
+
44
+ s.files = %w(Rakefile README.markdown) + Dir["{lib,spec}/**/*"]
45
+ s.require_path = "lib"
46
+
47
+ s.add_development_dependency 'rack-test', '~> 0.5.4'
48
+ s.add_development_dependency 'rake', '~> 0.8.7'
49
+ s.add_development_dependency 'rspec', '~> 2.0.0.beta.5'
50
+ s.add_development_dependency 'webrat', '~> 0.7.1'
51
+
52
+ s.add_dependency 'haml', '~> 3.0.12'
53
+ s.add_dependency 'sinatra', '~> 1.0'
54
+ end
55
+ Jeweler::GemcutterTasks.new
56
+ rescue LoadError
57
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
58
+ end
@@ -0,0 +1,41 @@
1
+ !!! 5
2
+
3
+ %html
4
+
5
+ %head
6
+ %title API Documentation
7
+ %link{ :rel => "stylesheet", :href => "/docs.css" }
8
+
9
+ %body
10
+
11
+ #content
12
+
13
+ %h1
14
+ %a{ :href => '/' } API Documentation
15
+
16
+ - docs.each do |doc|
17
+
18
+ .api
19
+
20
+ .url
21
+ %a
22
+ = doc[:verb].upcase
23
+ = doc[:uri]
24
+
25
+ .description
26
+ = doc[:description]
27
+
28
+ - if (doc[:params] || []).length > 0
29
+ .params
30
+ - doc[:params].each do |param|
31
+ .param
32
+ .type{ :class => (param[:required] && "required") }
33
+ = (param[:required]) ? "REQUIRED" : "OPTIONAL"
34
+ .name= escape_html(param[:name])
35
+ .description= param[:description]
36
+
37
+ %code.request
38
+ = display_code doc[:request]
39
+
40
+ %code.response
41
+ = display_code doc[:response]
@@ -0,0 +1,106 @@
1
+ *
2
+ :font-family Helvetica, Arial, sans-serif
3
+
4
+ =code_title
5
+ :display block
6
+ :padding 6px 10px
7
+ :font-weight bold
8
+ :background #ccc
9
+ :color #333
10
+ :margin-left -12px
11
+ :margin-right -12px
12
+ :margin-top -12px
13
+ :margin-bottom 12px
14
+
15
+ h2
16
+ :background #555
17
+ :color #fff
18
+ :border 1px #666 solid
19
+ :padding 10px
20
+ a
21
+ :color #fff
22
+ :text-decoration none
23
+
24
+ .api
25
+ :margin-bottom 24px
26
+ :background #eee
27
+ :border 1px #ccc solid
28
+
29
+ .url
30
+ :padding 6px 10px
31
+ :background #aaa
32
+ :border-bottom 1px #ccc solid
33
+ a
34
+ :color #333
35
+ :font-size 1.6em
36
+ :font-weight bold
37
+ :font-family monospace
38
+
39
+ .description
40
+ :padding 12px
41
+
42
+ code
43
+ :font-family Monaco, monospace
44
+ :white-space pre
45
+ :padding 12px
46
+ :display block
47
+
48
+ .params
49
+ :margin-bottom 10px
50
+ :padding 12px
51
+ :display block
52
+ &:before
53
+ +code_title
54
+ :content "Parameters"
55
+ .param
56
+ :line-height 30px
57
+ .name
58
+ :display inline
59
+ :font-weight bold
60
+ :font-family monospace
61
+ :font-size 1.2em
62
+ .type
63
+ :font-weight bold
64
+ :font-size 0.6em
65
+ :color #999
66
+ :display inline-block
67
+ :width 65px
68
+ .required
69
+ :color #333
70
+ .description
71
+ :display inline
72
+
73
+ .request
74
+ &:before
75
+ +code_title
76
+ :content "Request"
77
+
78
+ .response
79
+ &:before
80
+ +code_title
81
+ :content "Response"
82
+
83
+ body
84
+ :margin 0
85
+
86
+ #content
87
+ :width 800px
88
+ :margin-left auto
89
+ :margin-right auto
90
+
91
+ #index
92
+ .section
93
+ :margin-bottom 20px
94
+ .summarydoc
95
+ :border 1px #ccc solid
96
+ :padding 12px
97
+ :margin-top 10px
98
+ :background #eee
99
+ .path
100
+ :margin-bottom 10px
101
+ a
102
+ :font-family monospace
103
+ :font-weight bold
104
+ :font-size 1.4em
105
+ .description
106
+ :color #666
@@ -0,0 +1,108 @@
1
+ require "haml"
2
+ require "sinatra/base"
3
+
4
+ module Sinatra
5
+ module Croon
6
+ VERSION = "0.0.1"
7
+
8
+ def self.registered(app)
9
+ app.helpers Croon::Helpers
10
+ @app = app
11
+
12
+ app.get '/docs.css' do
13
+ pass do
14
+ content_type "text/css"
15
+ template = File.read(File.expand_path("../croon/views/docs.sass", __FILE__))
16
+ sass template
17
+ end
18
+ end
19
+
20
+ app.get '/docs' do
21
+ pass do
22
+ template = File.read(File.expand_path("../croon/views/docs.haml", __FILE__))
23
+ haml template, :locals => { :docs => documentation }
24
+ end
25
+ end
26
+ end
27
+
28
+ def self.route_added(verb, path, block)
29
+ return if verb.to_s == "HEAD"
30
+
31
+ route_location = caller(1).reject { |line| line =~ /sinatra\/base/ }.first
32
+ file, line = route_location.split(':')
33
+ doc = Croon::Parser.parse_route_documentation(file, line.to_i)
34
+
35
+ if doc[:description]
36
+ doc[:verb] = verb
37
+ doc[:uri] = path
38
+ @app.documentation << doc
39
+ end
40
+ end
41
+
42
+ def documentation
43
+ @documentation ||= []
44
+ end
45
+
46
+ module Helpers
47
+ def display_code(code)
48
+ Haml::Filters::Preserve.render(Haml::Filters::Escaped.render(code))
49
+ end
50
+
51
+ def documentation
52
+ self.class.documentation
53
+ end
54
+ end
55
+
56
+ module Parser
57
+ def self.parse_route_documentation(filename, line)
58
+ all_lines = File.read(filename).split("\n").reverse
59
+ index_start = all_lines.length - line + 1
60
+ num_lines = all_lines[index_start..-1].index { |l| !['', '#'].include?(l.strip[0..0]) }
61
+ doc_lines = all_lines[index_start, num_lines].reverse
62
+
63
+ parse_comments(doc_lines)
64
+ end
65
+
66
+ def self.parse_comments(comments)
67
+ key = :description
68
+
69
+ comments.inject({}) do |parsed, comment|
70
+ case comment.strip
71
+ when /\A#\s*@param\s+(.+?)\s+(.+)/ then
72
+ parsed[:params] ||= []
73
+ required = $1[0..0] == '<'
74
+ name = $1[1..-2]
75
+ parsed[:params] << { :name => name, :description => $2, :required => required }
76
+ when /\A#\s*@(\w+)\s*(.*)\Z/ then
77
+ key = $1.to_sym
78
+ parsed[key] ||= []
79
+ parsed[key] << $2 if $2
80
+ when /\A#(.+)\Z/ then
81
+ parsed[key] ||= []
82
+ parsed[key] << $1
83
+ end
84
+ parsed
85
+ end.inject({}) do |flattened, (k, v)|
86
+ case v.first
87
+ when String then
88
+ flattened[k] = strip_left(v.reject { |l| l.strip == "" }.join("\n"))
89
+ else
90
+ flattened[k] = v
91
+ end
92
+ flattened
93
+ end
94
+ end
95
+
96
+ def self.strip_left(code)
97
+ first_line = code.split("\n").first
98
+ return code unless first_line
99
+ num_spaces = first_line.match(/\A */)[0].length
100
+ code.split("\n").map do |line|
101
+ line[num_spaces..-1]
102
+ end.join("\n")
103
+ end
104
+ end
105
+ end
106
+
107
+ register Croon
108
+ end
@@ -0,0 +1,84 @@
1
+ require "spec_helper"
2
+ require "sinatra/base"
3
+ require "sinatra/croon"
4
+
5
+ class MockSinatraApp < Sinatra::Base
6
+ register Sinatra::Croon
7
+
8
+ # Show an application.
9
+ #
10
+ # @request GET /apps.json
11
+ # @response { "status" : "ok" }
12
+
13
+ get "/apps.json" do
14
+ # do something here
15
+ end
16
+
17
+ # Create an application.
18
+ #
19
+ # @param <name> the name of the application to create
20
+ # @param [stack] the stack on which to create the application
21
+ #
22
+ # @request
23
+ # POST /apps.json
24
+ # name=example&stack=bamboo-ree-1.8.7
25
+ #
26
+ # @response
27
+ # {
28
+ # "id": 1,
29
+ # "name": "example",
30
+ # "owner": "user@example.org",
31
+ # "created_at": "Sat Jan 01 00:00:00 UTC 2000",
32
+ # "stack": "bamboo-ree-1.8.7",
33
+ # "slug_size": 1000000,
34
+ # "repo_size": 500000,
35
+ # "dynos": 1,
36
+ # "workers": 0
37
+ # }
38
+
39
+ post "/apps.json" do
40
+ # do something here
41
+ end
42
+ end
43
+
44
+ describe Sinatra::Croon do
45
+ include Rack::Test::Methods
46
+ include Webrat::Matchers
47
+
48
+ let(:app) { MockSinatraApp.new }
49
+
50
+ it "can set a description" do
51
+ get "/docs"
52
+ last_response.should have_selector(".description", :content => "Show an application.")
53
+ last_response.should have_selector(".description", :content => "Create an application.")
54
+ end
55
+
56
+ it "can set params" do
57
+ get "/docs"
58
+ last_response.should have_selector(".param") do |param|
59
+ param.should have_selector(".type.required")
60
+ param.should have_selector(".name", :content => "name")
61
+ param.should have_selector(".description", :content => "the name of the application to create")
62
+ end
63
+ last_response.should have_selector(".param") do |param|
64
+ param.should have_selector(".name", :content => "stack")
65
+ param.should have_selector(".description", :content => "the stack on which to create the application")
66
+ end
67
+ end
68
+
69
+ it "can set a request" do
70
+ get "/docs"
71
+ last_response.should have_selector(".request", :content => "GET /apps.json")
72
+ end
73
+
74
+ it "can set a response" do
75
+ get "/docs"
76
+ last_response.should have_selector(".response", :content => '{ "status" : "ok" }')
77
+ end
78
+
79
+ it "has a default style" do
80
+ get "/docs.css"
81
+ last_response.should =~ /\.response/
82
+ end
83
+
84
+ end
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+ require "rack/test"
3
+ require "rspec"
4
+ require "webrat"
5
+ require "webrat/core/matchers"
6
+
7
+ $:.unshift "lib"
8
+
9
+ Rspec.configure do |config|
10
+ config.color_enabled = true
11
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-croon
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - David Dollar
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-07-21 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack-test
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ - 5
33
+ - 4
34
+ version: 0.5.4
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 49
46
+ segments:
47
+ - 0
48
+ - 8
49
+ - 7
50
+ version: 0.8.7
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 62196457
62
+ segments:
63
+ - 2
64
+ - 0
65
+ - 0
66
+ - beta
67
+ - 5
68
+ version: 2.0.0.beta.5
69
+ type: :development
70
+ version_requirements: *id003
71
+ - !ruby/object:Gem::Dependency
72
+ name: webrat
73
+ prerelease: false
74
+ requirement: &id004 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ hash: 1
80
+ segments:
81
+ - 0
82
+ - 7
83
+ - 1
84
+ version: 0.7.1
85
+ type: :development
86
+ version_requirements: *id004
87
+ - !ruby/object:Gem::Dependency
88
+ name: haml
89
+ prerelease: false
90
+ requirement: &id005 !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ~>
94
+ - !ruby/object:Gem::Version
95
+ hash: 31
96
+ segments:
97
+ - 3
98
+ - 0
99
+ - 12
100
+ version: 3.0.12
101
+ type: :runtime
102
+ version_requirements: *id005
103
+ - !ruby/object:Gem::Dependency
104
+ name: sinatra
105
+ prerelease: false
106
+ requirement: &id006 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ~>
110
+ - !ruby/object:Gem::Version
111
+ hash: 15
112
+ segments:
113
+ - 1
114
+ - 0
115
+ version: "1.0"
116
+ type: :runtime
117
+ version_requirements: *id006
118
+ description: Create documentation for an API built in Sinatra.
119
+ email: ddollar@gmail.com
120
+ executables: []
121
+
122
+ extensions: []
123
+
124
+ extra_rdoc_files:
125
+ - README.md
126
+ files:
127
+ - Rakefile
128
+ - lib/sinatra/croon.rb
129
+ - lib/sinatra/croon/views/docs.haml
130
+ - lib/sinatra/croon/views/docs.sass
131
+ - spec/sinatra/croon_spec.rb
132
+ - spec/spec_helper.rb
133
+ - README.md
134
+ has_rdoc: true
135
+ homepage: http://daviddollar.org/
136
+ licenses: []
137
+
138
+ post_install_message:
139
+ rdoc_options:
140
+ - --charset=UTF-8
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ hash: 3
149
+ segments:
150
+ - 0
151
+ version: "0"
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 3
158
+ segments:
159
+ - 0
160
+ version: "0"
161
+ requirements: []
162
+
163
+ rubyforge_project:
164
+ rubygems_version: 1.3.7
165
+ signing_key:
166
+ specification_version: 3
167
+ summary: Create documentation for an API built in Sinatra.
168
+ test_files:
169
+ - spec/sinatra/croon_spec.rb
170
+ - spec/spec_helper.rb