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
@@ -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 '.resource' do
9
- before(:each) do
10
- json = load_document('api.json').read
11
- api = Useless::Doc::Serialization::Load.api json
12
- result = Useless::Doc::UI::Godel.api(api)
13
- @doc = Nokogiri::HTML(result)
14
- end
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
- it 'should render the URL in the only h1' do
17
- h1s = @doc.css('h1')
18
- h1s.length.should == 1
19
- h1s.first.content.should == 'twonk.useless.io'
20
- end
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
- it 'should render the API description in a top-level p' do
23
- description = @doc.css('body > p')
24
- description.length.should == 1
25
- description.first.content.should == 'Twonk information. Duh.'
26
- end
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
- it 'should render resouce paths as h2s' do
29
- h2s = @doc.css('h2')
30
- h2s.length.should == 2
31
- h2s.map { |h2| h2.content }.should match_array(['/twonks/:id', '/twonks/:id/werp'])
32
- end
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
- it 'should render resouce descriptions as ps within the section' do
35
- ps = @doc.css('section > p')
36
- ps.length.should == 2
37
- ps.map { |h2| h2.content }.should match_array(['The most critical aspect.', 'That other shit.'])
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
- it 'should add a link for each method, with an appropriate description' do
41
- as = @doc.css('table td a')
42
- td_content = @doc.css('table td').map { |td| td.content }
43
- as.find { |a| a.content == 'GET' }['href'].should == '/twonks/:id#GET'
44
- td_content.should include 'Get dat twonk.'
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
- as.find { |a| a.content == 'POST' }['href'].should == '/twonks/:id/werp#POST'
47
- td_content.should include 'Make dem werps.'
48
- end
49
- end
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
- describe '.resource' do
52
- before(:each) do
53
- json = load_document('twonk.json').read
54
- resource = Useless::Doc::Serialization::Load.resource json
55
- result = Useless::Doc::UI::Godel.resource(resource)
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
- it 'should render the path within the only h1' do
60
- h1s = @doc.css('h1')
61
- h1s.length.should == 1
62
- h1s.first.content.should == '/twonks/:id'
63
- end
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
- it 'should render the methods as h2s' do
66
- h2s = @doc.css('h2')
67
- h2s.length.should == 2
68
- h2s.map { |h2| h2.content }.should match_array(['GET', 'PUT'])
69
- end
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
- it 'should render response codes as h3s' do
72
- h3s = @doc.css('h3')
73
- h3s.length.should == 3
74
- h3s.map { |h3| h3.content }.should match_array(['404', '200', '201'])
75
- end
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
- it 'should contain the method and response code descriptions in ps' do
78
- p_content = @doc.css('p').map { |p| p.content }
79
- p_content.should include 'The most critical aspect.'
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
- it 'should add parameter information to a table' do
87
- [
88
- { key: 'id', description: 'The ID of the desired twonk.' },
89
- { key: 'werp', description: 'Self-explanatory.' },
90
- { key: 'id', description: 'The ID of the twonk to be updated.' }
91
- ].each do |param|
92
- @doc.css('table').find do |table|
93
- table.content.match(param[:key]) and
94
- table.content.match(param[:description])
95
- end.should_not be_nil
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
- it 'should add body information to a table' do
100
- [
101
- { key: 'name', description: 'The name of the twonk.' },
102
- { key: 'created_by', description: 'The short name of the user who created the twonk.' },
103
- { key: 'hoinked_by', description: 'The ID of the person who hoinked this twonk.' }
104
- ].each do |attribute|
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(attribute[:key]) and
107
- table.content.match(attribute[:description])
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
- it 'should add header information to a table' do
113
- @doc.css('table').find do |table|
114
- table.content.match('User-Agent') and
115
- table.content.match('The thingy you\'re using.')
116
- end.should_not be_nil
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
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.add_dependency 'oj'
18
18
  gem.add_dependency 'rack'
19
19
  gem.add_dependency 'typhoeus'
20
- gem.add_dependency 'low'
20
+ gem.add_dependency 'low', '~> 0.0.15'
21
21
  gem.add_dependency 'sinatra'
22
22
  gem.add_dependency 'mustache'
23
23
 
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.2.3
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-01-16 00:00:00.000000000 Z
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: '0'
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: '0'
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/application.rb
179
- - lib/useless/doc/rack/proxy.rb
180
- - lib/useless/doc/rack/retriever.rb
181
- - lib/useless/doc/rack/stylesheet.rb
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/application_spec.rb
197
- - spec/useless/doc/rack/proxy_spec.rb
198
- - spec/useless/doc/rack/retriever_spec.rb
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/application_spec.rb
237
- - spec/useless/doc/rack/proxy_spec.rb
238
- - spec/useless/doc/rack/retriever_spec.rb
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