useless-doc 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/lib/useless/doc/client.rb +62 -0
  2. data/lib/useless/doc/core/api.rb +6 -2
  3. data/lib/useless/doc/core/domain.rb +34 -0
  4. data/lib/useless/doc/dsl.rb +30 -0
  5. data/lib/useless/doc/rack/{stylesheet.rb → css.rb} +8 -8
  6. data/lib/useless/doc/rack/html.rb +26 -0
  7. data/lib/useless/doc/rack/subject.rb +40 -0
  8. data/lib/useless/doc/rack/ui.rb +12 -11
  9. data/lib/useless/doc/rack/url.rb +33 -0
  10. data/lib/useless/doc/rack.rb +46 -0
  11. data/lib/useless/doc/router.rb +62 -0
  12. data/lib/useless/doc/serialization/dump.rb +17 -0
  13. data/lib/useless/doc/serialization/load.rb +35 -0
  14. data/lib/useless/doc/sinatra.rb +4 -3
  15. data/lib/useless/doc/ui/godel/api.mustache +24 -24
  16. data/lib/useless/doc/ui/godel/domain.mustache +26 -0
  17. data/lib/useless/doc/ui/godel/resource.mustache +151 -155
  18. data/lib/useless/doc/ui/godel/stylesheet.css +156 -1
  19. data/lib/useless/doc/ui/godel.rb +54 -12
  20. data/lib/useless/doc/ui.rb +24 -0
  21. data/lib/useless/doc/version.rb +1 -1
  22. data/lib/useless/doc.rb +20 -2
  23. data/spec/config.ru +19 -0
  24. data/spec/documents/api.json +1 -0
  25. data/spec/documents/domain.json +17 -0
  26. data/spec/useless/doc/client_spec.rb +59 -0
  27. data/spec/useless/doc/dsl_spec.rb +28 -2
  28. data/spec/useless/doc/rack/{stylesheet_spec.rb → css_spec.rb} +3 -9
  29. data/spec/useless/doc/rack/html_spec.rb +39 -0
  30. data/spec/useless/doc/rack/subject_spec.rb +44 -0
  31. data/spec/useless/doc/rack/ui_spec.rb +1 -1
  32. data/spec/useless/doc/rack/url_spec.rb +35 -0
  33. data/spec/useless/doc/{rack/application_spec.rb → rack_spec.rb} +22 -11
  34. data/spec/useless/doc/router_spec.rb +38 -0
  35. data/spec/useless/doc/serialization/dump_spec.rb +29 -0
  36. data/spec/useless/doc/serialization/load_spec.rb +37 -0
  37. data/spec/useless/doc/sinatra_spec.rb +3 -1
  38. data/spec/useless/doc/ui/godel_spec.rb +136 -96
  39. data/useless-doc.gemspec +1 -1
  40. metadata +34 -21
  41. data/lib/useless/doc/rack/application.rb +0 -47
  42. data/lib/useless/doc/rack/proxy.rb +0 -62
  43. data/lib/useless/doc/rack/retriever.rb +0 -68
  44. data/lib/useless/doc/rack/transform.rb +0 -46
  45. data/spec/useless/doc/rack/proxy_spec.rb +0 -56
  46. data/spec/useless/doc/rack/retriever_spec.rb +0 -82
  47. data/spec/useless/doc/rack/transform_spec.rb +0 -57
@@ -6,167 +6,163 @@
6
6
  </head>
7
7
  <body>
8
8
 
9
- <h1>{{path}}</h1>
10
-
11
- <p>{{description}}</p>
12
-
13
- {{#requests}}
14
- <section>
15
- <h2>{{method}}</h2>
16
-
17
- <p>{{description}}</p>
18
-
19
- <ul>
20
- <li>{{authentication_requirement}}</li>
21
- </ul>
22
-
23
- {{#parameters?}}
24
- <section>
25
- <h4>Parameters</h4>
26
- <table>
27
- <th>
28
- <tr>
29
- <td>Name</td>
30
- <td>Type</td>
31
- <td>Required</td>
32
- <td>Default</td>
33
- <td>Description</td>
34
- <tr>
35
- </th>
36
- <tbody>
37
- {{#parameters}}
9
+ <header class="resource">
10
+ <h1>{{path}}</h1>
11
+
12
+ <p class="description resource">{{description}}</p>
13
+ </header>
14
+
15
+ <section class="main requests">
16
+ {{#requests}}
17
+ <article>
18
+ <h2 id="{{method}}">{{method}}</h2>
19
+
20
+ <p class="description request">{{description}}</p>
21
+
22
+ <ul class="attributes">
23
+ <li>{{authentication_requirement}}</li>
24
+ </ul>
25
+
26
+ {{#parameters?}}
27
+ <section class="parameters">
28
+ <h4>Parameters</h4>
29
+ <table>
30
+ <thead>
31
+ <tr>
32
+ <th>Name</th>
33
+ <th>Description</th>
34
+ <th>Type</th>
35
+ <th>Required</th>
36
+ <th>Default</th>
38
37
  <tr>
39
- <td>{{key}}</td>
40
- <td>{{type}}</td>
41
- <td>{{required}}</td>
42
- <td>{{default}}</td>
43
- <td>{{description}}</td>
44
- </tr>
45
- {{/parameters}}
46
- </tbody>
47
- </table>
48
- </section>
49
- {{/parameters?}}
50
-
51
- {{#headers?}}
52
- <section>
53
- <h4>Headers</h4>
54
- <table>
55
- <th>
56
- <tr>
57
- <td>Name</td>
58
- <td>Description</td>
59
- <tr>
60
- </th>
61
- <tbody>
62
- {{#headers}}
38
+ </thead>
39
+ <tbody>
40
+ {{#parameters}}
41
+ <tr>
42
+ <td>{{key}}</td>
43
+ <td>{{description}}</td>
44
+ <td>{{type}}</td>
45
+ <td>{{required}}</td>
46
+ <td>{{default}}</td>
47
+ </tr>
48
+ {{/parameters}}
49
+ </tbody>
50
+ </table>
51
+ </section> <!-- class="parameters" -->
52
+ {{/parameters?}}
53
+
54
+ {{#headers?}}
55
+ <section class="headers">
56
+ <h4>Headers</h4>
57
+ <table>
58
+ <thead>
63
59
  <tr>
64
- <td>{{key}}</td>
65
- <td>{{description}}</td>
66
- </tr>
67
- {{/headers}}
68
- </tbody>
69
- </table>
70
- </section>
71
- {{/headers?}}
72
-
73
- {{#body}}
74
- <section>
75
- <h4>Body</h4>
76
-
77
- <ul>
78
- <li>{{content_type}}</li>
79
- </ul>
80
-
81
- <table>
82
- <th>
83
- <tr>
84
- <td>Name</td>
85
- <td>Type</td>
86
- <td>Required</td>
87
- <td>Default</td>
88
- <td>Description</td>
89
- <tr>
90
- </th>
91
- <tbody>
92
- {{#attributes}}
60
+ <th>Name</th>
61
+ <th>Description</th>
93
62
  <tr>
94
- <td>{{key}}</td>
95
- <td>{{type}}</td>
96
- <td>{{required}}</td>
97
- <td>{{default}}</td>
98
- <td>{{description}}</td>
99
- </tr>
100
- {{/attributes}}
101
- </tbody>
102
- </table>
103
- </section>
104
- {{/body}}
105
-
106
- {{#responses}}
107
- <section>
108
- <h3>{{code}}</h3>
109
-
110
- <p>{{description}}</p>
111
-
112
- {{#headers?}}
113
- <section>
114
- <h4>Headers</h4>
115
- <table>
116
- <th>
63
+ </thead>
64
+ <tbody>
65
+ {{#headers}}
117
66
  <tr>
118
- <td>Name</td>
119
- <td>Description</td>
67
+ <td>{{key}}</td>
68
+ <td>{{description}}</td>
69
+ </tr>
70
+ {{/headers}}
71
+ </tbody>
72
+ </table>
73
+ </section> <!-- class="headers" -->
74
+ {{/headers?}}
75
+
76
+ {{#body}}
77
+ <section class="body">
78
+ <h4>Body <span class="content-type">{{content_type}}</span></h4>
79
+
80
+ <table>
81
+ <thead>
82
+ <tr>
83
+ <th>Name</th>
84
+ <th>Description</th>
85
+ <th>Type</th>
86
+ <th>Required</th>
87
+ <th>Default</th>
88
+ <tr>
89
+ </thead>
90
+ <tbody>
91
+ {{#attributes}}
120
92
  <tr>
121
- </th>
122
- <tbody>
123
- {{#headers}}
93
+ <td>{{key}}</td>
94
+ <td>{{description}}</td>
95
+ <td>{{type}}</td>
96
+ <td>{{required}}</td>
97
+ <td>{{default}}</td>
98
+ </tr>
99
+ {{/attributes}}
100
+ </tbody>
101
+ </table>
102
+ </section> <!-- class="body" -->
103
+ {{/body}}
104
+
105
+ {{#responses}}
106
+ <section class="response">
107
+ <h3>{{code}} <span class="status-message">{{status_message}}</h3>
108
+
109
+ <p class="description response">{{description}}</p>
110
+
111
+ {{#headers?}}
112
+ <section>
113
+ <h4>Headers</h4>
114
+ <table>
115
+ <thead>
124
116
  <tr>
125
- <td>{{key}}</td>
126
- <td>{{description}}</td>
127
- </tr>
128
- {{/headers}}
129
- </tbody>
130
- </table>
131
- </section>
132
- {{/headers?}}
133
-
134
- {{#body}}
135
- <section>
136
- <h4>Body</h4>
137
-
138
- <ul>
139
- <li>{{content_type}}</li>
140
- </ul>
141
-
142
- <table>
143
- <th>
144
- <tr>
145
- <td>Name</td>
146
- <td>Type</td>
147
- <td>Required</td>
148
- <td>Default</td>
149
- <td>Description</td>
150
- <tr>
151
- </th>
152
- <tbody>
153
- {{#attributes}}
117
+ <th>Name</th>
118
+ <th>Description</th>
119
+ <tr>
120
+ </thead>
121
+ <tbody>
122
+ {{#headers}}
123
+ <tr>
124
+ <td>{{key}}</td>
125
+ <td>{{description}}</td>
126
+ </tr>
127
+ {{/headers}}
128
+ </tbody>
129
+ </table>
130
+ </section>
131
+ {{/headers?}}
132
+
133
+ {{#body}}
134
+ <section>
135
+ <h4>Body <span class="content-type">{{content_type}}</span></h4>
136
+
137
+ <table>
138
+ <thead>
139
+ <tr>
140
+ <th>Name</th>
141
+ <th>Description</th>
142
+ <th>Type</th>
143
+ <th>Required</th>
144
+ <th>Default</th>
154
145
  <tr>
155
- <td>{{key}}</td>
156
- <td>{{type}}</td>
157
- <td>{{required}}</td>
158
- <td>{{default}}</td>
159
- <td>{{description}}</td>
160
- </tr>
161
- {{/attributes}}
162
- </tbody>
163
- </table>
164
- </section>
165
- {{/body}}
166
-
167
- </section>
168
- {{/responses}}
169
- </section>
170
- {{/requests}}
146
+ </thead>
147
+ <tbody>
148
+ {{#attributes}}
149
+ <tr>
150
+ <td>{{key}}</td>
151
+ <td>{{description}}</td>
152
+ <td>{{type}}</td>
153
+ <td>{{required}}</td>
154
+ <td>{{default}}</td>
155
+ </tr>
156
+ {{/attributes}}
157
+ </tbody>
158
+ </table>
159
+ </section>
160
+ {{/body}}
161
+
162
+ </section>
163
+ {{/responses}}
164
+ </article>
165
+ {{/requests}}
166
+ </section class="requests">
171
167
 
172
168
  </body>
@@ -1 +1,156 @@
1
- body { color: #333; }
1
+ @import url(http://fonts.googleapis.com/css?family=Open+Sans:300|Open+Sans+Condensed:300,700);
2
+
3
+ body {
4
+ font-family: 'Open Sans', sans-serif;
5
+ color: #333;
6
+ margin: 0;
7
+ }
8
+
9
+ h1, h2, h3, h4 {
10
+ font-family: 'Open Sans Condensed', sans-serif;
11
+ margin-top: 0;
12
+ margin-bottom: 0.25em;
13
+ }
14
+
15
+ h2 {
16
+ font-size: 2.5em;
17
+ margin-bottom: 0;
18
+ }
19
+
20
+ h3 {
21
+ font-size: 2em;
22
+ margin-bottom: 0;
23
+ }
24
+
25
+ h3 span.status-message {
26
+ color: #BBB;
27
+ font-weight: normal;
28
+ }
29
+
30
+ h4 span.content-type {
31
+ font-weight: normal;
32
+ font-family: 'Open Sans';
33
+ color: #999999;
34
+ margin-left: 1em;
35
+ font-size: 0.75em;
36
+ }
37
+
38
+ p.description {
39
+ color: #888;
40
+ margin-top: 0;
41
+ }
42
+
43
+ p.description.request {
44
+ margin-bottom: 0.5em;
45
+ }
46
+
47
+ header {
48
+ position: fixed;
49
+ min-height: 100%;
50
+ min-width: 260px;
51
+ padding: 10px 20px;
52
+ border-right: 3px double #DDD;
53
+ }
54
+
55
+ header h1,
56
+ header p {
57
+ width: 260px;
58
+ }
59
+
60
+ header.domain h1,
61
+ header.api h1 {
62
+ margin-bottom: 1em;
63
+ }
64
+
65
+ header section.header-section {
66
+ margin-bottom: 3em;
67
+ }
68
+
69
+ header section.header-section.api {
70
+ margin-bottom: 1.5em;
71
+ }
72
+
73
+ header section.header-section p {
74
+ margin-bottom: 0.75em;
75
+ }
76
+
77
+ header section.header-section a.header-section-title {
78
+ font-size: 1.5em;
79
+ font-family: 'Open Sans Condensed', sans-serif;
80
+ }
81
+
82
+ header section.header-section td.description {
83
+ font-size: 0.9em;
84
+ }
85
+
86
+ section.main {
87
+ position: relative;
88
+ margin-left: 313px;
89
+ min-width: 520px;
90
+ }
91
+
92
+ section.main article {
93
+ padding: 30px 40px 40px;
94
+ border-bottom: 3px double #DDD;
95
+ }
96
+
97
+ section.main article:last-child {
98
+ padding-bottom: 30px;
99
+ border-bottom: 0 none;
100
+ }
101
+
102
+ section.parameters,
103
+ section.headers,
104
+ section.body {
105
+ margin-bottom: 2em;
106
+ }
107
+
108
+ section.response {
109
+ margin-bottom: 1em;
110
+ }
111
+
112
+ ul.attributes {
113
+ overflow: hidden;
114
+ *zoom: 1;
115
+ padding: 0;
116
+ margin: 0;
117
+ list-style: none;
118
+ margin-bottom: 2em;
119
+ }
120
+
121
+ ul.attributes li {
122
+ float: left;
123
+ padding: 3px 10px;
124
+ border: 1px solid #DDD;
125
+ background-color: #EEE;
126
+ font-size: 0.8em;
127
+ }
128
+
129
+ table {
130
+ width: 100%;
131
+ border: 1px solid #DDD;
132
+ border-spacing: 0;
133
+ }
134
+
135
+ table th {
136
+ font-weight: inherit;
137
+ }
138
+
139
+ table td, th {
140
+ border-right: 1px solid #DDD;
141
+ border-bottom: 1px solid #DDD;
142
+ padding: 5px;
143
+ }
144
+
145
+ table th {
146
+ text-align: left;
147
+ color: #999;
148
+ }
149
+
150
+ table td:last-child, table th:last-child {
151
+ border-right-width: 0;
152
+ }
153
+
154
+ table tbody tr:last-child td, table tbody tr:last-child th {
155
+ border-bottom-width: 0;
156
+ }
@@ -1,39 +1,76 @@
1
1
  require 'mustache'
2
2
  require 'forwardable'
3
+ require 'rack/utils'
4
+
5
+ require 'useless/doc/core/domain'
6
+ require 'useless/doc/core/api'
7
+ require 'useless/doc/core/resource'
3
8
 
4
9
  module Useless
5
10
  module Doc
6
11
  module UI
7
12
  class Godel
8
- def self.api(api)
9
- API.new(api).render
13
+ include Doc::UI
14
+
15
+ def self.asset_path
16
+ File.dirname(__FILE__) + '/godel'
10
17
  end
11
18
 
12
- def self.resource(resource)
13
- Resource.new(resource).render
19
+ def initialize(router)
20
+ @router = router
14
21
  end
15
22
 
16
- def self.css
17
- File.read(asset_path + '/stylesheet.css')
23
+ def html(entity)
24
+ view = case entity
25
+ when Core::Domain then Godel::Domain
26
+ when Core::API then Godel::API
27
+ when Core::Resource then Godel::Resource
28
+ end
29
+
30
+ if view
31
+ view.new(entity, @router).render
32
+ end
18
33
  end
19
34
 
20
- def self.asset_path
21
- File.dirname(__FILE__) + '/godel'
35
+ def css(entity = nil)
36
+ File.read(Godel.asset_path + '/stylesheet.css')
37
+ end
38
+
39
+ class Domain < Mustache
40
+ extend Forwardable
41
+
42
+ def_delegators :@domain, :name, :description
43
+
44
+ self.template_file = Godel.asset_path + '/domain.mustache'
45
+
46
+ def initialize(domain, router = nil)
47
+ @domain = domain
48
+ @router = router
49
+ end
50
+
51
+ def apis
52
+ @domain.apis.map{ |api| Godel::API.new(api, @router) }
53
+ end
22
54
  end
23
55
 
24
56
  class API < Mustache
25
57
  extend Forwardable
26
58
 
27
- def_delegators :@api, :url, :description
59
+ def_delegators :@api, :name, :url, :description
28
60
 
29
61
  self.template_file = Godel.asset_path + '/api.mustache'
30
62
 
31
- def initialize(api)
63
+ def initialize(api, router)
32
64
  @api = api
65
+ @router = router
66
+ end
67
+
68
+ def doc_url
69
+ @router.doc_for_api(@api.url)
33
70
  end
34
71
 
35
72
  def resources
36
- @api.resources.map{ |resource| Godel::Resource.new(resource) }
73
+ @api.resources.map{ |resource| Godel::Resource.new(resource, @router) }
37
74
  end
38
75
  end
39
76
 
@@ -44,8 +81,9 @@ module Useless
44
81
 
45
82
  self.template_file = Godel.asset_path + '/resource.mustache'
46
83
 
47
- def initialize(resource)
84
+ def initialize(resource, router)
48
85
  @resource = resource
86
+ @router = router
49
87
  end
50
88
 
51
89
  def requests
@@ -97,6 +135,10 @@ module Useless
97
135
  @response = response
98
136
  end
99
137
 
138
+ def status_message
139
+ ::Rack::Utils::HTTP_STATUS_CODES[code]
140
+ end
141
+
100
142
  def headers?
101
143
  headers.any?
102
144
  end
@@ -0,0 +1,24 @@
1
+ module Useless
2
+ module Doc
3
+
4
+ # A +Doc::UI+ is a class that has two methods: +#html+ and +#css+. It is
5
+ # initialized with an instance of +Doc::Router+.
6
+ #
7
+ # +#html+ takes a +Doc::Core+ entity and returns a corresponding HTML
8
+ # representation.
9
+ #
10
+ # +#css+ returns a CSS document suitable for the HTML returned by +#html+.
11
+ #
12
+ module UI
13
+ def initialize(router)
14
+ @router = router
15
+ end
16
+
17
+ def html(entity)
18
+ end
19
+
20
+ def css(entity = nil)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,5 @@
1
1
  module Useless
2
2
  module Doc
3
- VERSION = '0.2.3'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end
data/lib/useless/doc.rb CHANGED
@@ -1,9 +1,27 @@
1
1
  require 'useless/doc/dsl'
2
+ require 'useless/doc/serialization/load'
3
+ require 'useless/doc/serialization/dump'
2
4
 
3
5
  module Useless
4
6
  module Doc
5
- def self.api(url, &block)
6
- DSL::API.build url: url, &block
7
+ def self.domain(name = nil, &block)
8
+ DSL::Domain.build name: name, &block
9
+ end
10
+
11
+ def self.api(name = nil, &block)
12
+ DSL::API.build name: name, &block
13
+ end
14
+
15
+ def self.resource(path = nil, &block)
16
+ DSL::Resource.build path: path, &block
17
+ end
18
+
19
+ def self.load
20
+ Useless::Doc::Serialization::Load
21
+ end
22
+
23
+ def self.dump
24
+ Useless::Doc::Serialization::Dump
7
25
  end
8
26
  end
9
27
  end
data/spec/config.ru ADDED
@@ -0,0 +1,19 @@
1
+ lib = File.expand_path('../../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'uri'
5
+ require 'useless/doc/router'
6
+ require 'useless/doc/rack'
7
+
8
+ class TestRouter
9
+ include Useless::Doc::Router
10
+
11
+ def api_for_doc(url)
12
+ if uri = URI(url)
13
+ path = uri.path == '/' ? '/domain' : uri.path
14
+ "#{uri.scheme}://#{uri.host}#{path}"
15
+ end
16
+ end
17
+ end
18
+
19
+ run Useless::Doc::Rack.new(TestRouter.new)
@@ -1,4 +1,5 @@
1
1
  {
2
+ "name": "Twonk API",
2
3
  "url": "twonk.useless.io",
3
4
  "description": "Twonk information. Duh.",
4
5
  "resources": [