useless-doc 0.1.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/.gitignore +18 -0
- data/.rbenv-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +3 -0
- data/Rakefile +1 -0
- data/config.ru +4 -0
- data/lib/useless/doc/action.rb +50 -0
- data/lib/useless/doc/body.rb +58 -0
- data/lib/useless/doc/dsl.rb +208 -0
- data/lib/useless/doc/header.rb +24 -0
- data/lib/useless/doc/rack/application.rb +31 -0
- data/lib/useless/doc/rack/proxy.rb +58 -0
- data/lib/useless/doc/rack/stylesheet.rb +24 -0
- data/lib/useless/doc/rack/transform.rb +35 -0
- data/lib/useless/doc/rack/ui.rb +35 -0
- data/lib/useless/doc/request/parameter.rb +47 -0
- data/lib/useless/doc/request.rb +29 -0
- data/lib/useless/doc/resource.rb +29 -0
- data/lib/useless/doc/response/status.rb +27 -0
- data/lib/useless/doc/response.rb +29 -0
- data/lib/useless/doc/serialization/dump.rb +122 -0
- data/lib/useless/doc/serialization/load.rb +171 -0
- data/lib/useless/doc/sinatra.rb +48 -0
- data/lib/useless/doc/ui/godel/stylesheet.css +1 -0
- data/lib/useless/doc/ui/godel/template.mustache +199 -0
- data/lib/useless/doc/ui/godel.rb +92 -0
- data/lib/useless/doc/ui.rb +37 -0
- data/lib/useless/doc/version.rb +5 -0
- data/lib/useless/doc.rb +4 -0
- data/spec/documents/twonk.json +106 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/useless/doc/dsl_spec.rb +71 -0
- data/spec/useless/doc/proxy_spec.rb +48 -0
- data/spec/useless/doc/serialization/dump_spec.rb +116 -0
- data/spec/useless/doc/serialization/load_spec.rb +99 -0
- data/spec/useless/doc/sinatra_spec.rb +64 -0
- data/useless-doc.gemspec +26 -0
- metadata +217 -0
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p327
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Kevin Hyland
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/config.ru
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Documentation for an action on a API resource.
|
5
|
+
#
|
6
|
+
# @!attribute [r] description
|
7
|
+
# @return [String] a description of the action.
|
8
|
+
#
|
9
|
+
# @!attribute [r] method
|
10
|
+
# @return [String] the action's HTTP method.
|
11
|
+
# @see Useless::Doc::Action::Method
|
12
|
+
#
|
13
|
+
# @!attribute [r] authentication_required
|
14
|
+
# @return [Boolean] whether or not the user needs to authenticate in
|
15
|
+
# order to perform this action.
|
16
|
+
#
|
17
|
+
# @!attribute [r] request
|
18
|
+
# @return [Request] the request documentation for the action.
|
19
|
+
#
|
20
|
+
# @!attribute [r] response
|
21
|
+
# @return [Response] the response documentation for the action.
|
22
|
+
#
|
23
|
+
class Action
|
24
|
+
|
25
|
+
module Method
|
26
|
+
GET = 'GET'
|
27
|
+
HEAD = 'HEAD'
|
28
|
+
POST = 'POST'
|
29
|
+
PUT = 'PUT'
|
30
|
+
PATCH = 'PATCH'
|
31
|
+
DELETE = 'DELETE'
|
32
|
+
TRACE = 'TRACE'
|
33
|
+
CONNECT = 'CONNECT'
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :description, :method, :authentication_required,
|
37
|
+
:request, :response
|
38
|
+
|
39
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
40
|
+
#
|
41
|
+
def initialize(attrs = {})
|
42
|
+
@description = attrs[:description]
|
43
|
+
@method = attrs[:method]
|
44
|
+
@authentication_required = attrs[:authentication_required]
|
45
|
+
@request = attrs[:request]
|
46
|
+
@response = attrs[:response]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Documentation for an HTTP body, belonging either to the request or the
|
5
|
+
# response.
|
6
|
+
#
|
7
|
+
# @!attribute [r] content_type
|
8
|
+
# @return [String] the MIME type of the body.
|
9
|
+
#
|
10
|
+
# @!attribute [r] attributes
|
11
|
+
# @return [Array<Body::Attribute>] documentation for each of the body
|
12
|
+
# attributes.
|
13
|
+
#
|
14
|
+
class Body
|
15
|
+
|
16
|
+
attr_reader :content_type, :attributes
|
17
|
+
|
18
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
19
|
+
#
|
20
|
+
def initialize(attrs)
|
21
|
+
@content_type = attrs[:content_type]
|
22
|
+
@attributes = attrs[:attributes]
|
23
|
+
end
|
24
|
+
|
25
|
+
# Documentation for an attribute on an HTTP body.
|
26
|
+
#
|
27
|
+
# @!attribute [r] key
|
28
|
+
# @return [String] the key of this attribute in the body.
|
29
|
+
#
|
30
|
+
# @!attribute [r] value_type
|
31
|
+
# @return [String] one of "string", "number", "object",
|
32
|
+
# "array", or "boolean". "string" is the default value.
|
33
|
+
#
|
34
|
+
# @!attribute [r] required
|
35
|
+
# @return [Boolean] whether or not the attribute is required. If it
|
36
|
+
# is required, and the attribute is omitted, the response should have
|
37
|
+
# a 4xx code. +true+ is the default value.
|
38
|
+
#
|
39
|
+
# @!attribute [r] description
|
40
|
+
# @return [String] a description of the attribute.
|
41
|
+
#
|
42
|
+
class Attribute
|
43
|
+
|
44
|
+
attr_reader :key, :type, :required, :default, :description
|
45
|
+
|
46
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
47
|
+
#
|
48
|
+
def initialize(attrs)
|
49
|
+
@key = attrs[:key]
|
50
|
+
@type = attrs[:type] || 'string'
|
51
|
+
@required = attrs.key?(:required) ? attrs[:required] : true
|
52
|
+
@default = attrs[:default]
|
53
|
+
@description = attrs[:description]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'useless/doc/action'
|
2
|
+
require 'useless/doc/body'
|
3
|
+
require 'useless/doc/header'
|
4
|
+
require 'useless/doc/request'
|
5
|
+
require 'useless/doc/request/parameter'
|
6
|
+
require 'useless/doc/resource'
|
7
|
+
require 'useless/doc/response'
|
8
|
+
require 'useless/doc/response/status'
|
9
|
+
|
10
|
+
module Useless
|
11
|
+
module Doc
|
12
|
+
|
13
|
+
# A simple DSL for building resource documentation.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# Useless::Doc::DSL::Resource.build do
|
17
|
+
# path '/resources'
|
18
|
+
# description 'The entire collection of resources.'
|
19
|
+
#
|
20
|
+
# get 'Returns a full listing of the resources.' do
|
21
|
+
# authentication_required false
|
22
|
+
#
|
23
|
+
# request do
|
24
|
+
# parameter 'page', 'The page of resources to be returned.'
|
25
|
+
# header 'X-Twiddle', 'The twiddle threshold.'
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# response do
|
29
|
+
# status 200, 'The resources were returned successfully.'
|
30
|
+
#
|
31
|
+
# header 'X-Twonk', 'The twonk coefficient.'
|
32
|
+
#
|
33
|
+
# body do
|
34
|
+
# content_type 'application/json'
|
35
|
+
# attribute 'name', 'The name of the resource.', required: true
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
class DSL
|
42
|
+
|
43
|
+
module Member
|
44
|
+
module ClassMethods
|
45
|
+
def build(attributes = {}, &block)
|
46
|
+
resource = new(attributes)
|
47
|
+
resource.instance_eval(&block)
|
48
|
+
resource.generate
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.included(base)
|
53
|
+
base.send(:extend, ClassMethods)
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(attributes = {})
|
57
|
+
@attributes = default_attributes.merge(attributes)
|
58
|
+
end
|
59
|
+
|
60
|
+
def generate
|
61
|
+
name = self.class.name.split('::').last
|
62
|
+
klass = eval("Doc::#{name}")
|
63
|
+
klass.new(@attributes)
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_attributes
|
67
|
+
{}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Resource
|
72
|
+
include DSL::Member
|
73
|
+
|
74
|
+
def default_attributes
|
75
|
+
{ actions: [] }
|
76
|
+
end
|
77
|
+
|
78
|
+
def path(path)
|
79
|
+
@attributes[:path] = path
|
80
|
+
end
|
81
|
+
|
82
|
+
def description(description)
|
83
|
+
@attributes[:description] = description
|
84
|
+
end
|
85
|
+
|
86
|
+
def get(description = nil, &block)
|
87
|
+
method(Doc::Action::Method::GET, description, &block)
|
88
|
+
end
|
89
|
+
|
90
|
+
def head(description = nil, &block)
|
91
|
+
method(Doc::Action::Method::HEAD, description, &block)
|
92
|
+
end
|
93
|
+
|
94
|
+
def post(description = nil, &block)
|
95
|
+
method(Doc::Action::Method::POST, description, &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def put(description = nil, &block)
|
99
|
+
method(Doc::Action::Method::PUT, description, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def patch(description = nil, &block)
|
103
|
+
method(Doc::Action::Method::PATCH, description, &block)
|
104
|
+
end
|
105
|
+
|
106
|
+
def delete(description = nil, &block)
|
107
|
+
method(Doc::Action::Method::DELETE, description, &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
def trace(description = nil, &block)
|
111
|
+
method(Doc::Action::Method::TRACE, description, &block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def connect(description = nil, &block)
|
115
|
+
method(Doc::Action::Method::CONNECT, description, &block)
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def method(type, description, &block)
|
121
|
+
attributes = { method: type, description: description }
|
122
|
+
@attributes[:actions] << Action.build(attributes, &block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
class Action
|
127
|
+
include DSL::Member
|
128
|
+
|
129
|
+
def description(description)
|
130
|
+
@attributes[:description] = description
|
131
|
+
end
|
132
|
+
|
133
|
+
def authentication_required(value = nil)
|
134
|
+
@attributes[:authentication_required] = value.nil? ? true : value
|
135
|
+
end
|
136
|
+
|
137
|
+
def request(&block)
|
138
|
+
@attributes[:request] = Request.build({}, &block)
|
139
|
+
end
|
140
|
+
|
141
|
+
def response(&block)
|
142
|
+
@attributes[:response] = Response.build({}, &block)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Request
|
147
|
+
include DSL::Member
|
148
|
+
|
149
|
+
def default_attributes
|
150
|
+
{ parameters: [], headers: [] }
|
151
|
+
end
|
152
|
+
|
153
|
+
def parameter(key, description, attributes = {})
|
154
|
+
parameter = Doc::Request::Parameter.new attributes.merge(key: key, description: description)
|
155
|
+
@attributes[:parameters] << parameter
|
156
|
+
end
|
157
|
+
|
158
|
+
def header(key, description)
|
159
|
+
header = Doc::Header.new key: key, description: description
|
160
|
+
@attributes[:headers] << header
|
161
|
+
end
|
162
|
+
|
163
|
+
def body(&block)
|
164
|
+
@attributes[:body] = Body.build({}, &block)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class Response
|
169
|
+
include DSL::Member
|
170
|
+
|
171
|
+
def default_attributes
|
172
|
+
{ statuses: [], headers: [] }
|
173
|
+
end
|
174
|
+
|
175
|
+
def status(code, description)
|
176
|
+
status = Doc::Response::Status.new code: code, description: description
|
177
|
+
@attributes[:statuses] << status
|
178
|
+
end
|
179
|
+
|
180
|
+
def header(key, description)
|
181
|
+
header = Doc::Header.new key: key, description: description
|
182
|
+
@attributes[:headers] << header
|
183
|
+
end
|
184
|
+
|
185
|
+
def body(&block)
|
186
|
+
@attributes[:body] = Body.build({}, &block)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class Body
|
191
|
+
include DSL::Member
|
192
|
+
|
193
|
+
def default_attributes
|
194
|
+
{ attributes: [] }
|
195
|
+
end
|
196
|
+
|
197
|
+
def content_type(value)
|
198
|
+
@attributes[:content_type] = value
|
199
|
+
end
|
200
|
+
|
201
|
+
def attribute(key, description, attributes = {})
|
202
|
+
attribute = Doc::Body::Attribute.new attributes.merge(key: key, description: description)
|
203
|
+
@attributes[:attributes] << attribute
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Documentation for an HTTP header, belonging either to the request or the
|
5
|
+
# response.
|
6
|
+
#
|
7
|
+
# @!attribute [r] key
|
8
|
+
# @return [String] the key of the header.
|
9
|
+
#
|
10
|
+
# @!attribute [r] description
|
11
|
+
# @return [String] a description of the header.
|
12
|
+
#
|
13
|
+
class Header
|
14
|
+
attr_accessor :key, :description
|
15
|
+
|
16
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
17
|
+
#
|
18
|
+
def initialize(attrs = {})
|
19
|
+
@key = attrs[:key]
|
20
|
+
@description = attrs[:description]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
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/stylesheet'
|
9
|
+
require 'useless/doc/rack/transform'
|
10
|
+
require 'useless/doc/rack/ui'
|
11
|
+
|
12
|
+
module Useless
|
13
|
+
module Doc
|
14
|
+
module Rack
|
15
|
+
module Application
|
16
|
+
def self.call(env)
|
17
|
+
::Rack::Builder.app do
|
18
|
+
use Low::Rack::RackErrors
|
19
|
+
use Low::Rack::RequestLogger
|
20
|
+
use ::Rack::CommonLogger
|
21
|
+
use Useless::Doc::Rack::UI
|
22
|
+
use Useless::Doc::Rack::Stylesheet
|
23
|
+
use Useless::Doc::Rack::Transform
|
24
|
+
|
25
|
+
run Useless::Doc::Rack::Proxy.new
|
26
|
+
end.call(env)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'typhoeus'
|
3
|
+
require 'rack/request'
|
4
|
+
|
5
|
+
module Useless
|
6
|
+
module Doc
|
7
|
+
module Rack
|
8
|
+
|
9
|
+
# +Doc::Proxy+ is a Rack app that provides an HTML interface to Useless
|
10
|
+
# API documentation. It assumes that each API resource responds to INFO
|
11
|
+
# requests with documentation JSON that corresponds to the format
|
12
|
+
# specified by +Doc::Serialization::Load+.
|
13
|
+
#
|
14
|
+
# It proxies requests according to a simple convention. For example, a
|
15
|
+
# GET request to some-api.doc.useless.io/some/resource will result in an
|
16
|
+
# OPTIONS request to some-api.useless.io/some/resource.
|
17
|
+
#
|
18
|
+
# If there is no corresponding endpoint, the proxy will respond with a
|
19
|
+
# 404.
|
20
|
+
#
|
21
|
+
class Proxy
|
22
|
+
|
23
|
+
def self.transform_url(url)
|
24
|
+
uri = URI(url)
|
25
|
+
new_host = uri.host.gsub(/\.doc\./, '.')
|
26
|
+
"#{uri.scheme}://#{new_host}#{uri.path}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def call(env)
|
30
|
+
request = ::Rack::Request.new(env)
|
31
|
+
url = Proxy.transform_url(request.url)
|
32
|
+
|
33
|
+
if json = retrieve_resource(url)
|
34
|
+
[200, {'Content-Type' => 'application/json'}, [json]]
|
35
|
+
else
|
36
|
+
[404, {'Content-Type' => 'text/plain'}, ['Documentation JSON is missing.']]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def retrieve_resource(url)
|
41
|
+
response = Typhoeus.options url, headers: { 'Accept' => 'application/json' }
|
42
|
+
response.response_body
|
43
|
+
end
|
44
|
+
|
45
|
+
# +Proxy::Stub+ retrieves JSON from the spec/documents directory for
|
46
|
+
# easy UI testing.
|
47
|
+
#
|
48
|
+
class Stub < Proxy
|
49
|
+
def retrieve_resource(url)
|
50
|
+
uri = URI(url)
|
51
|
+
path = File.dirname(__FILE__) + "/../../../../spec/documents#{uri.path}.json"
|
52
|
+
File.read(path)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
module Rack
|
4
|
+
|
5
|
+
# +Doc::Rack::Stylesheet+ serves the stylesheet for the current +Doc::UI+
|
6
|
+
# iff the request path is '/doc.css'. Otherwise, it passes the request
|
7
|
+
# through.
|
8
|
+
#
|
9
|
+
class Stylesheet
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
if env["PATH_INFO"].to_s == '/doc.css'
|
16
|
+
[200, {'Content-Type' => 'text/css'}, [env['useless.doc.ui'].css]]
|
17
|
+
else
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
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
|
+
response = @app.call(env)
|
20
|
+
|
21
|
+
if response[0] == 200 and response[1]['Content-Type'] == 'application/json'
|
22
|
+
begin
|
23
|
+
resource = Serialization::Load.resource(response[2].first)
|
24
|
+
[200, {'Content-Type' => 'text/html'}, [env['useless.doc.ui'].html(resource)]]
|
25
|
+
rescue Oj::ParseError
|
26
|
+
[502, {'Content-Type' => 'text/plain'}, ['Documentation JSON is malformed.']]
|
27
|
+
end
|
28
|
+
else
|
29
|
+
response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
require 'useless/doc/ui/godel'
|
3
|
+
|
4
|
+
module Useless
|
5
|
+
module Doc
|
6
|
+
module Rack
|
7
|
+
|
8
|
+
# +Doc::Rack::UI+ chooses which UI should be used to render the
|
9
|
+
# documentation. It can theoretically be chosen via the 'ui' parameter,
|
10
|
+
# but for now it will alway choose +Godel+
|
11
|
+
#
|
12
|
+
class UI
|
13
|
+
def self.default
|
14
|
+
Useless::Doc::UI::Godel
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(app)
|
18
|
+
@app = app
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
request = ::Rack::Request.new(env)
|
23
|
+
|
24
|
+
ui = case request.params['ui']
|
25
|
+
when 'godel' then Useless::Doc::UI::Godel
|
26
|
+
else Rack::UI.default
|
27
|
+
end
|
28
|
+
|
29
|
+
env['useless.doc.ui'] = ui
|
30
|
+
@app.call(env)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
class Request
|
4
|
+
|
5
|
+
# Documentation for a request parameter for an API action.
|
6
|
+
#
|
7
|
+
# @!attribute [r] type
|
8
|
+
# @return [String] either "path" if it's part of the URL path, or
|
9
|
+
# "query" if it's part of the query string.
|
10
|
+
#
|
11
|
+
# @!attribute [r] key
|
12
|
+
# @return [String] the key of the parameter.
|
13
|
+
#
|
14
|
+
# @!attribute [r] required
|
15
|
+
# @return [Boolean] whether or not the parameter is required. If it is
|
16
|
+
# required, and the attribute is omitted, the response should have a
|
17
|
+
# 4xx code.
|
18
|
+
#
|
19
|
+
# @!attribute [r] default
|
20
|
+
# @return [String, Numeric] the value used if the parameter is omitted
|
21
|
+
# and is not required.
|
22
|
+
#
|
23
|
+
# @!attribute [r] description
|
24
|
+
# @return [String] a description of the parameter.
|
25
|
+
#
|
26
|
+
class Parameter
|
27
|
+
|
28
|
+
module Type
|
29
|
+
PATH = 'path'
|
30
|
+
QUERY = 'query'
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :type, :key, :required, :default, :description
|
34
|
+
|
35
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
36
|
+
#
|
37
|
+
def initialize(attrs = {})
|
38
|
+
@type = attrs[:type]
|
39
|
+
@key = attrs[:key]
|
40
|
+
@required = attrs[:required]
|
41
|
+
@default = attrs[:default]
|
42
|
+
@description = attrs[:description]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Useless
|
2
|
+
module Doc
|
3
|
+
|
4
|
+
# Documentation for an HTTP request.
|
5
|
+
#
|
6
|
+
# @!attribute [r] parameters
|
7
|
+
# @return [Array<Request::Parameter] documentation for the parameters
|
8
|
+
# of the request.
|
9
|
+
#
|
10
|
+
# @!attribute [r] headers
|
11
|
+
# @return [Array<Header>] documentation for the headers of the
|
12
|
+
# request.
|
13
|
+
#
|
14
|
+
# @!attribute [r] body
|
15
|
+
# @return [Body] documentation for the body of the request.
|
16
|
+
#
|
17
|
+
class Request
|
18
|
+
attr_accessor :parameters, :headers, :body
|
19
|
+
|
20
|
+
# @param [Hash] attrs corresponds to the class's instance attributes.
|
21
|
+
#
|
22
|
+
def initialize(attrs = {})
|
23
|
+
@parameters = attrs[:parameters]
|
24
|
+
@headers = attrs[:headers]
|
25
|
+
@body = attrs[:body]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|