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.
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