useless-doc 0.2.3 → 0.3.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.
- data/lib/useless/doc/client.rb +62 -0
- data/lib/useless/doc/core/api.rb +6 -2
- data/lib/useless/doc/core/domain.rb +34 -0
- data/lib/useless/doc/dsl.rb +30 -0
- data/lib/useless/doc/rack/{stylesheet.rb → css.rb} +8 -8
- data/lib/useless/doc/rack/html.rb +26 -0
- data/lib/useless/doc/rack/subject.rb +40 -0
- data/lib/useless/doc/rack/ui.rb +12 -11
- data/lib/useless/doc/rack/url.rb +33 -0
- data/lib/useless/doc/rack.rb +46 -0
- data/lib/useless/doc/router.rb +62 -0
- data/lib/useless/doc/serialization/dump.rb +17 -0
- data/lib/useless/doc/serialization/load.rb +35 -0
- data/lib/useless/doc/sinatra.rb +4 -3
- data/lib/useless/doc/ui/godel/api.mustache +24 -24
- data/lib/useless/doc/ui/godel/domain.mustache +26 -0
- data/lib/useless/doc/ui/godel/resource.mustache +151 -155
- data/lib/useless/doc/ui/godel/stylesheet.css +156 -1
- data/lib/useless/doc/ui/godel.rb +54 -12
- data/lib/useless/doc/ui.rb +24 -0
- data/lib/useless/doc/version.rb +1 -1
- data/lib/useless/doc.rb +20 -2
- data/spec/config.ru +19 -0
- data/spec/documents/api.json +1 -0
- data/spec/documents/domain.json +17 -0
- data/spec/useless/doc/client_spec.rb +59 -0
- data/spec/useless/doc/dsl_spec.rb +28 -2
- data/spec/useless/doc/rack/{stylesheet_spec.rb → css_spec.rb} +3 -9
- data/spec/useless/doc/rack/html_spec.rb +39 -0
- data/spec/useless/doc/rack/subject_spec.rb +44 -0
- data/spec/useless/doc/rack/ui_spec.rb +1 -1
- data/spec/useless/doc/rack/url_spec.rb +35 -0
- data/spec/useless/doc/{rack/application_spec.rb → rack_spec.rb} +22 -11
- data/spec/useless/doc/router_spec.rb +38 -0
- data/spec/useless/doc/serialization/dump_spec.rb +29 -0
- data/spec/useless/doc/serialization/load_spec.rb +37 -0
- data/spec/useless/doc/sinatra_spec.rb +3 -1
- data/spec/useless/doc/ui/godel_spec.rb +136 -96
- data/useless-doc.gemspec +1 -1
- metadata +34 -21
- data/lib/useless/doc/rack/application.rb +0 -47
- data/lib/useless/doc/rack/proxy.rb +0 -62
- data/lib/useless/doc/rack/retriever.rb +0 -68
- data/lib/useless/doc/rack/transform.rb +0 -46
- data/spec/useless/doc/rack/proxy_spec.rb +0 -56
- data/spec/useless/doc/rack/retriever_spec.rb +0 -82
- data/spec/useless/doc/rack/transform_spec.rb +0 -57
@@ -1,125 +1,165 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
2
|
|
3
3
|
require 'nokogiri'
|
4
|
+
require 'useless/doc'
|
5
|
+
require 'useless/doc/router'
|
4
6
|
require 'useless/doc/ui/godel'
|
5
|
-
require 'useless/doc/serialization/load'
|
6
7
|
|
7
8
|
describe Useless::Doc::UI::Godel do
|
8
|
-
describe '.
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
describe '.html' do
|
10
|
+
context 'for a Core::Domain instance' do
|
11
|
+
before(:all) do
|
12
|
+
router = Useless::Doc::Router.default
|
13
|
+
json = load_document('domain.json').read
|
14
|
+
domain = Useless::Doc.load.domain(json)
|
15
|
+
result = Useless::Doc::UI::Godel.new(router).html(domain)
|
16
|
+
@doc = Nokogiri::HTML(result)
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
19
|
+
it 'should render the name in the only h1' do
|
20
|
+
h1s = @doc.css('h1')
|
21
|
+
h1s.length.should == 1
|
22
|
+
h1s.first.content.should == 'Useless'
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
it 'should render the domain description in an article p' do
|
26
|
+
description = @doc.css('article p.description.domain')
|
27
|
+
description.length.should == 1
|
28
|
+
description.first.content.should == 'A collection of useless APIs.'
|
29
|
+
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
it 'should render API names as a\'s, with correct doc URLs' do
|
32
|
+
as = @doc.css('a.name')
|
33
|
+
as.length.should == 2
|
34
|
+
as.map { |a| a.content }.should match_array(['The Jah API', 'The Twonk API'])
|
35
|
+
as.map { |a| a['href'] }.should match_array(['http://jah.doc.useless.io', 'http://twonk.doc.useless.io'])
|
36
|
+
end
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
it 'should render API descriptions as ps within the section' do
|
39
|
+
ps = @doc.css('section > p')
|
40
|
+
ps.length.should == 2
|
41
|
+
ps.map { |h2| h2.content }.should match_array(['Jah, jah, jah.', 'TWONK!!!'])
|
42
|
+
end
|
38
43
|
end
|
39
44
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
context 'for a Core::API instance' do
|
46
|
+
before(:all) do
|
47
|
+
json = load_document('api.json').read
|
48
|
+
router = Useless::Doc::Router.default
|
49
|
+
api = Useless::Doc.load.api(json)
|
50
|
+
result = Useless::Doc::UI::Godel.new(router).html(api)
|
51
|
+
@doc = Nokogiri::HTML(result)
|
52
|
+
end
|
45
53
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
54
|
+
it 'should render the URL in the only h1' do
|
55
|
+
h1s = @doc.css('h1')
|
56
|
+
h1s.length.should == 1
|
57
|
+
h1s.first.content.should == 'Twonk API'
|
58
|
+
end
|
50
59
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
@doc = Nokogiri::HTML(result)
|
57
|
-
end
|
60
|
+
it 'should render the API description in an article p' do
|
61
|
+
description = @doc.css('article p.description.api')
|
62
|
+
description.length.should == 1
|
63
|
+
description.first.content.should == 'Twonk information. Duh.'
|
64
|
+
end
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
it 'should render resouce paths as a\'s' do
|
67
|
+
as = @doc.css('a.path')
|
68
|
+
as.length.should == 2
|
69
|
+
as.map { |a| a.content }.should match_array(['/twonks/:id', '/twonks/:id/werp'])
|
70
|
+
end
|
64
71
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
72
|
+
it 'should render resouce descriptions as ps within the section' do
|
73
|
+
ps = @doc.css('section > p')
|
74
|
+
ps.length.should == 2
|
75
|
+
ps.map { |h2| h2.content }.should match_array(['The most critical aspect.', 'That other shit.'])
|
76
|
+
end
|
70
77
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
78
|
+
it 'should add a link for each method, with an appropriate description' do
|
79
|
+
as = @doc.css('table td a')
|
80
|
+
td_content = @doc.css('table td').map { |td| td.content }
|
81
|
+
as.find { |a| a.content == 'GET' }['href'].should == '/twonks/:id#GET'
|
82
|
+
td_content.should include 'Get dat twonk.'
|
76
83
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
p_content.should include 'Retrieve a representation of an individual twonk.'
|
81
|
-
p_content.should include 'A twonk with the specified ID could not be found.'
|
82
|
-
p_content.should include 'The specified twonk was retrieved successfully.'
|
83
|
-
p_content.should include 'The specified twonk was updated successfully.'
|
84
|
+
as.find { |a| a.content == 'POST' }['href'].should == '/twonks/:id/werp#POST'
|
85
|
+
td_content.should include 'Make dem werps.'
|
86
|
+
end
|
84
87
|
end
|
85
88
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@doc
|
93
|
-
|
94
|
-
|
95
|
-
|
89
|
+
context 'for a Core::Resource instance' do
|
90
|
+
before(:each) do
|
91
|
+
json = load_document('twonk.json').read
|
92
|
+
router = Useless::Doc::Router.default
|
93
|
+
resource = Useless::Doc.load.resource json
|
94
|
+
result = Useless::Doc::UI::Godel.new(router).html(resource)
|
95
|
+
@doc = Nokogiri::HTML(result)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should render the path within the only h1' do
|
99
|
+
h1s = @doc.css('h1')
|
100
|
+
h1s.length.should == 1
|
101
|
+
h1s.first.content.should == '/twonks/:id'
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should render the methods as h2s' do
|
105
|
+
h2s = @doc.css('h2')
|
106
|
+
h2s.length.should == 2
|
107
|
+
h2s.map { |h2| h2.content }.should match_array(['GET', 'PUT'])
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should render response codes as h3s' do
|
111
|
+
h3s = @doc.css('h3')
|
112
|
+
h3s.length.should == 3
|
113
|
+
h3s.map { |h3| h3.content }.should match_array(['404 Not Found', '200 OK', '201 Created'])
|
96
114
|
end
|
97
|
-
end
|
98
115
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
116
|
+
it 'should contain the method and response code descriptions in ps' do
|
117
|
+
p_content = @doc.css('p').map { |p| p.content }
|
118
|
+
p_content.should include 'The most critical aspect.'
|
119
|
+
p_content.should include 'Retrieve a representation of an individual twonk.'
|
120
|
+
p_content.should include 'A twonk with the specified ID could not be found.'
|
121
|
+
p_content.should include 'The specified twonk was retrieved successfully.'
|
122
|
+
p_content.should include 'The specified twonk was updated successfully.'
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should add parameter information to a table' do
|
126
|
+
[
|
127
|
+
{ key: 'id', description: 'The ID of the desired twonk.' },
|
128
|
+
{ key: 'werp', description: 'Self-explanatory.' },
|
129
|
+
{ key: 'id', description: 'The ID of the twonk to be updated.' }
|
130
|
+
].each do |param|
|
131
|
+
@doc.css('table').find do |table|
|
132
|
+
table.content.match(param[:key]) and
|
133
|
+
table.content.match(param[:description])
|
134
|
+
end.should_not be_nil
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should add body information to a table' do
|
139
|
+
[
|
140
|
+
{ key: 'name', description: 'The name of the twonk.' },
|
141
|
+
{ key: 'created_by', description: 'The short name of the user who created the twonk.' },
|
142
|
+
{ key: 'hoinked_by', description: 'The ID of the person who hoinked this twonk.' }
|
143
|
+
].each do |attribute|
|
144
|
+
@doc.css('table').find do |table|
|
145
|
+
table.content.match(attribute[:key]) and
|
146
|
+
table.content.match(attribute[:description])
|
147
|
+
end.should_not be_nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should add header information to a table' do
|
105
152
|
@doc.css('table').find do |table|
|
106
|
-
table.content.match(
|
107
|
-
table.content.match(
|
153
|
+
table.content.match('User-Agent') and
|
154
|
+
table.content.match('The thingy you\'re using.')
|
108
155
|
end.should_not be_nil
|
109
156
|
end
|
110
|
-
end
|
111
157
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'should include authentication information in lis' do
|
120
|
-
li_content = @doc.css('li').map { |li| li.content }
|
121
|
-
li_content.should include 'Authentication Required'
|
122
|
-
li_content.should include 'Authentication Not Required'
|
158
|
+
it 'should include authentication information in lis' do
|
159
|
+
li_content = @doc.css('li').map { |li| li.content }
|
160
|
+
li_content.should include 'Authentication Required'
|
161
|
+
li_content.should include 'Authentication Not Required'
|
162
|
+
end
|
123
163
|
end
|
124
164
|
end
|
125
165
|
end
|
data/useless-doc.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: useless-doc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-02-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: oj
|
@@ -64,17 +64,17 @@ dependencies:
|
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: 0.0.15
|
70
70
|
type: :runtime
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
75
|
+
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: 0.0.15
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
79
|
name: sinatra
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,37 +168,46 @@ files:
|
|
168
168
|
- README.md
|
169
169
|
- Rakefile
|
170
170
|
- lib/useless/doc.rb
|
171
|
+
- lib/useless/doc/client.rb
|
171
172
|
- lib/useless/doc/core/api.rb
|
172
173
|
- lib/useless/doc/core/body.rb
|
174
|
+
- lib/useless/doc/core/domain.rb
|
173
175
|
- lib/useless/doc/core/header.rb
|
174
176
|
- lib/useless/doc/core/request.rb
|
175
177
|
- lib/useless/doc/core/resource.rb
|
176
178
|
- lib/useless/doc/core/response.rb
|
177
179
|
- lib/useless/doc/dsl.rb
|
178
|
-
- lib/useless/doc/rack
|
179
|
-
- lib/useless/doc/rack/
|
180
|
-
- lib/useless/doc/rack/
|
181
|
-
- lib/useless/doc/rack/
|
182
|
-
- lib/useless/doc/rack/transform.rb
|
180
|
+
- lib/useless/doc/rack.rb
|
181
|
+
- lib/useless/doc/rack/css.rb
|
182
|
+
- lib/useless/doc/rack/html.rb
|
183
|
+
- lib/useless/doc/rack/subject.rb
|
183
184
|
- lib/useless/doc/rack/ui.rb
|
185
|
+
- lib/useless/doc/rack/url.rb
|
186
|
+
- lib/useless/doc/router.rb
|
184
187
|
- lib/useless/doc/serialization/dump.rb
|
185
188
|
- lib/useless/doc/serialization/load.rb
|
186
189
|
- lib/useless/doc/sinatra.rb
|
190
|
+
- lib/useless/doc/ui.rb
|
187
191
|
- lib/useless/doc/ui/godel.rb
|
188
192
|
- lib/useless/doc/ui/godel/api.mustache
|
193
|
+
- lib/useless/doc/ui/godel/domain.mustache
|
189
194
|
- lib/useless/doc/ui/godel/resource.mustache
|
190
195
|
- lib/useless/doc/ui/godel/stylesheet.css
|
191
196
|
- lib/useless/doc/version.rb
|
197
|
+
- spec/config.ru
|
192
198
|
- spec/documents/api.json
|
199
|
+
- spec/documents/domain.json
|
193
200
|
- spec/documents/twonk.json
|
194
201
|
- spec/spec_helper.rb
|
202
|
+
- spec/useless/doc/client_spec.rb
|
195
203
|
- spec/useless/doc/dsl_spec.rb
|
196
|
-
- spec/useless/doc/rack/
|
197
|
-
- spec/useless/doc/rack/
|
198
|
-
- spec/useless/doc/rack/
|
199
|
-
- spec/useless/doc/rack/stylesheet_spec.rb
|
200
|
-
- spec/useless/doc/rack/transform_spec.rb
|
204
|
+
- spec/useless/doc/rack/css_spec.rb
|
205
|
+
- spec/useless/doc/rack/html_spec.rb
|
206
|
+
- spec/useless/doc/rack/subject_spec.rb
|
201
207
|
- spec/useless/doc/rack/ui_spec.rb
|
208
|
+
- spec/useless/doc/rack/url_spec.rb
|
209
|
+
- spec/useless/doc/rack_spec.rb
|
210
|
+
- spec/useless/doc/router_spec.rb
|
202
211
|
- spec/useless/doc/serialization/dump_spec.rb
|
203
212
|
- spec/useless/doc/serialization/load_spec.rb
|
204
213
|
- spec/useless/doc/sinatra_spec.rb
|
@@ -229,16 +238,20 @@ signing_key:
|
|
229
238
|
specification_version: 3
|
230
239
|
summary: For parsing and serving Useless documentation.
|
231
240
|
test_files:
|
241
|
+
- spec/config.ru
|
232
242
|
- spec/documents/api.json
|
243
|
+
- spec/documents/domain.json
|
233
244
|
- spec/documents/twonk.json
|
234
245
|
- spec/spec_helper.rb
|
246
|
+
- spec/useless/doc/client_spec.rb
|
235
247
|
- spec/useless/doc/dsl_spec.rb
|
236
|
-
- spec/useless/doc/rack/
|
237
|
-
- spec/useless/doc/rack/
|
238
|
-
- spec/useless/doc/rack/
|
239
|
-
- spec/useless/doc/rack/stylesheet_spec.rb
|
240
|
-
- spec/useless/doc/rack/transform_spec.rb
|
248
|
+
- spec/useless/doc/rack/css_spec.rb
|
249
|
+
- spec/useless/doc/rack/html_spec.rb
|
250
|
+
- spec/useless/doc/rack/subject_spec.rb
|
241
251
|
- spec/useless/doc/rack/ui_spec.rb
|
252
|
+
- spec/useless/doc/rack/url_spec.rb
|
253
|
+
- spec/useless/doc/rack_spec.rb
|
254
|
+
- spec/useless/doc/router_spec.rb
|
242
255
|
- spec/useless/doc/serialization/dump_spec.rb
|
243
256
|
- spec/useless/doc/serialization/load_spec.rb
|
244
257
|
- spec/useless/doc/sinatra_spec.rb
|
@@ -1,47 +0,0 @@
|
|
1
|
-
require 'rack/builder'
|
2
|
-
require 'rack/commonlogger'
|
3
|
-
require 'rack/reloader'
|
4
|
-
require 'low/rack/rack_errors'
|
5
|
-
require 'low/rack/request_logger'
|
6
|
-
|
7
|
-
require 'useless/doc/rack/proxy'
|
8
|
-
require 'useless/doc/rack/retriever'
|
9
|
-
require 'useless/doc/rack/stylesheet'
|
10
|
-
require 'useless/doc/rack/transform'
|
11
|
-
require 'useless/doc/rack/ui'
|
12
|
-
|
13
|
-
module Useless
|
14
|
-
module Doc
|
15
|
-
module Rack
|
16
|
-
class Application
|
17
|
-
def initialize(*subdomains)
|
18
|
-
@subdomains = subdomains
|
19
|
-
end
|
20
|
-
|
21
|
-
def call(env)
|
22
|
-
app.call(env)
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def app
|
28
|
-
@app ||= begin
|
29
|
-
subdomains = @subdomains
|
30
|
-
|
31
|
-
::Rack::Builder.app do
|
32
|
-
use Low::Rack::RackErrors
|
33
|
-
use Low::Rack::RequestLogger
|
34
|
-
use ::Rack::CommonLogger
|
35
|
-
use Useless::Doc::Rack::UI
|
36
|
-
use Useless::Doc::Rack::Stylesheet
|
37
|
-
use Useless::Doc::Rack::Retriever
|
38
|
-
use Useless::Doc::Rack::Transform
|
39
|
-
|
40
|
-
run Useless::Doc::Rack::Proxy.new(subdomains)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,62 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'rack/request'
|
3
|
-
|
4
|
-
module Useless
|
5
|
-
module Doc
|
6
|
-
module Rack
|
7
|
-
|
8
|
-
# +Doc::Proxy+ is a Rack app that provides an HTML interface to Useless
|
9
|
-
# API documentation. It assumes that each API resource responds to INFO
|
10
|
-
# requests with documentation JSON that corresponds to the format
|
11
|
-
# specified by +Doc::Serialization::Load+.
|
12
|
-
#
|
13
|
-
# It proxies requests according to a simple convention. For example, a
|
14
|
-
# GET request to some-api.doc.useless.io/some/resource will result in an
|
15
|
-
# OPTIONS request to some-api.useless.io/some/resource.
|
16
|
-
#
|
17
|
-
# If there is no corresponding endpoint, the proxy will respond with a
|
18
|
-
# 404. If the requested subdomain is not in the list of supported
|
19
|
-
# subdomains specified at initialization, the proxy will also respond
|
20
|
-
# with a 404.
|
21
|
-
#
|
22
|
-
class Proxy
|
23
|
-
|
24
|
-
def initialize(subdomains)
|
25
|
-
@subdomains = subdomains
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.transform_url(url)
|
29
|
-
uri = URI(url)
|
30
|
-
new_host = uri.host.gsub(/\.doc\./, '.')
|
31
|
-
"#{uri.scheme}://#{new_host}#{uri.path}"
|
32
|
-
end
|
33
|
-
|
34
|
-
def call(env)
|
35
|
-
unless env['useless.doc.retriever']
|
36
|
-
raise 'No retriever specified.'
|
37
|
-
end
|
38
|
-
|
39
|
-
request = ::Rack::Request.new(env)
|
40
|
-
|
41
|
-
if valid_subdomain?(request.url)
|
42
|
-
url = Proxy.transform_url(request.url)
|
43
|
-
|
44
|
-
if json = env['useless.doc.retriever'].retrieve(url)
|
45
|
-
[200, {'Content-Type' => 'application/json'}, [json]]
|
46
|
-
else
|
47
|
-
[404, {'Content-Type' => 'text/plain'}, ['Documentation JSON is missing.']]
|
48
|
-
end
|
49
|
-
else
|
50
|
-
[404, {'Content-Type' => 'text/plain'}, ['Unknown subdomain.']]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def valid_subdomain?(url)
|
57
|
-
@subdomains.include?(url[/((?:\w|\-)+)\.doc\./, 1])
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'time'
|
2
|
-
require 'typhoeus'
|
3
|
-
|
4
|
-
module Useless
|
5
|
-
module Doc
|
6
|
-
module Rack
|
7
|
-
|
8
|
-
# +Doc::Rack::Retriever+ sets an appropriate retriever for the current
|
9
|
-
# RACK_ENV. In production it uses the +Standard+ retriever which makes
|
10
|
-
# real HTTP calls. Elsewhere, it uses +Stub+ which servers corresponding
|
11
|
-
# files from the spec/documents directory.
|
12
|
-
#
|
13
|
-
class Retriever
|
14
|
-
def initialize(app)
|
15
|
-
@app = app
|
16
|
-
end
|
17
|
-
|
18
|
-
def call(env)
|
19
|
-
if ENV['RACK_ENV'] == 'production'
|
20
|
-
env['useless.doc.retriever'] = Standard
|
21
|
-
else
|
22
|
-
env['useless.doc.retriever'] = Stub
|
23
|
-
end
|
24
|
-
|
25
|
-
@app.call(env)
|
26
|
-
end
|
27
|
-
|
28
|
-
module Standard
|
29
|
-
NotModified = 304
|
30
|
-
|
31
|
-
@cache = {}
|
32
|
-
|
33
|
-
def self.retrieve(url)
|
34
|
-
headers = { 'Accept' => 'application/json' }
|
35
|
-
|
36
|
-
if @cache[url]
|
37
|
-
headers['If-Modified-Since'] = @cache[url].timestamp.httpdate()
|
38
|
-
end
|
39
|
-
|
40
|
-
response = Typhoeus.options url, headers: headers
|
41
|
-
|
42
|
-
unless response.response_code == NotModified
|
43
|
-
@cache[url] = CacheItem.new(response.response_body, Time.now)
|
44
|
-
end
|
45
|
-
|
46
|
-
@cache[url].response_body
|
47
|
-
end
|
48
|
-
|
49
|
-
class CacheItem
|
50
|
-
attr_accessor :response_body, :timestamp
|
51
|
-
|
52
|
-
def initialize(response_body, timestamp)
|
53
|
-
@response_body, @timestamp = response_body, timestamp
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
class Stub
|
59
|
-
def self.retrieve(url)
|
60
|
-
uri = URI(url)
|
61
|
-
path = File.dirname(__FILE__) + "/../../../../spec/documents#{uri.path}.json"
|
62
|
-
File.read(path)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'useless/doc/serialization/load'
|
2
|
-
|
3
|
-
module Useless
|
4
|
-
module Doc
|
5
|
-
module Rack
|
6
|
-
|
7
|
-
# +Doc::Rack::Transform+ takes the a JSON response and attempts to parse
|
8
|
-
# it via +Doc::Serialization::Load+ and render it as HTML via the UI
|
9
|
-
# specified by env['useless.doc.ui'].
|
10
|
-
#
|
11
|
-
# If the JSON cannot be parsed, the response will be a 502.
|
12
|
-
#
|
13
|
-
class Transform
|
14
|
-
def initialize(app)
|
15
|
-
@app = app
|
16
|
-
end
|
17
|
-
|
18
|
-
def call(env)
|
19
|
-
unless env['useless.doc.ui']
|
20
|
-
raise 'No UI specified.'
|
21
|
-
end
|
22
|
-
|
23
|
-
response = @app.call(env)
|
24
|
-
|
25
|
-
if response[0] == 200
|
26
|
-
begin
|
27
|
-
if env['PATH_INFO'] == '/'
|
28
|
-
api = Serialization::Load.api(response[2].first)
|
29
|
-
html = env['useless.doc.ui'].api(api)
|
30
|
-
else
|
31
|
-
resource = Serialization::Load.resource(response[2].first)
|
32
|
-
html = env['useless.doc.ui'].resource(resource)
|
33
|
-
end
|
34
|
-
|
35
|
-
[200, {'Content-Type' => 'text/html'}, [html]]
|
36
|
-
rescue Oj::ParseError
|
37
|
-
[502, {'Content-Type' => 'text/plain'}, ['Documentation JSON is malformed.']]
|
38
|
-
end
|
39
|
-
else
|
40
|
-
response
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|