swaggard 0.0.4
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +178 -0
- data/Rakefile +24 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.eot +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.svg +411 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.ttf +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.woff +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.woff2 +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.eot +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.svg +403 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.ttf +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.woff +0 -0
- data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.woff2 +0 -0
- data/app/assets/images/swaggard/logo_small.png +0 -0
- data/app/assets/images/swaggard/pet_store_api.png +0 -0
- data/app/assets/images/swaggard/throbber.gif +0 -0
- data/app/assets/images/swaggard/wordnik_api.png +0 -0
- data/app/assets/javascripts/swaggard/application.js +24 -0
- data/app/assets/javascripts/swaggard/lib/MD5.js +319 -0
- data/app/assets/javascripts/swaggard/lib/backbone-min.js +15 -0
- data/app/assets/javascripts/swaggard/lib/handlebars-1.0.rc.1.js +1920 -0
- data/app/assets/javascripts/swaggard/lib/handlebars-2.0.0.js +28 -0
- data/app/assets/javascripts/swaggard/lib/highlight.7.3.pack.js +1 -0
- data/app/assets/javascripts/swaggard/lib/jquery-1.8.0.min.js +2 -0
- data/app/assets/javascripts/swaggard/lib/jquery.ba-bbq.min.js +18 -0
- data/app/assets/javascripts/swaggard/lib/jquery.slideto.min.js +1 -0
- data/app/assets/javascripts/swaggard/lib/jquery.wiggle.min.js +8 -0
- data/app/assets/javascripts/swaggard/lib/marked.js +1272 -0
- data/app/assets/javascripts/swaggard/lib/shred.bundle.js +2765 -0
- data/app/assets/javascripts/swaggard/lib/swagger-client.js +3294 -0
- data/app/assets/javascripts/swaggard/lib/swagger.js +794 -0
- data/app/assets/javascripts/swaggard/lib/underscore-min.js +32 -0
- data/app/assets/javascripts/swaggard/swagger-ui.js +2240 -0
- data/app/assets/javascripts/swaggard/swagger-ui_org.js +2005 -0
- data/app/assets/stylesheets/swaggard/application.css +16 -0
- data/app/assets/stylesheets/swaggard/reset.css +125 -0
- data/app/assets/stylesheets/swaggard/screen.css.scss +1256 -0
- data/app/assets/stylesheets/swaggard/typography.css.scss +26 -0
- data/app/controllers/swaggard/application_controller.rb +4 -0
- data/app/controllers/swaggard/swagger_controller.rb +21 -0
- data/app/views/swaggard/swagger/index.html.erb +74 -0
- data/config/routes.rb +3 -0
- data/lib/swaggard.rb +92 -0
- data/lib/swaggard/api_definition.rb +52 -0
- data/lib/swaggard/configuration.rb +82 -0
- data/lib/swaggard/engine.rb +18 -0
- data/lib/swaggard/parsers/controllers.rb +30 -0
- data/lib/swaggard/parsers/models.rb +29 -0
- data/lib/swaggard/parsers/routes.rb +54 -0
- data/lib/swaggard/swagger/definition.rb +24 -0
- data/lib/swaggard/swagger/operation.rb +98 -0
- data/lib/swaggard/swagger/parameters/base.rb +21 -0
- data/lib/swaggard/swagger/parameters/body.rb +67 -0
- data/lib/swaggard/swagger/parameters/form.rb +32 -0
- data/lib/swaggard/swagger/parameters/list.rb +46 -0
- data/lib/swaggard/swagger/parameters/path.rb +21 -0
- data/lib/swaggard/swagger/parameters/query.rb +32 -0
- data/lib/swaggard/swagger/path.rb +24 -0
- data/lib/swaggard/swagger/property.rb +23 -0
- data/lib/swaggard/swagger/response.rb +45 -0
- data/lib/swaggard/swagger/tag.rb +28 -0
- data/lib/swaggard/swagger/type.rb +72 -0
- data/lib/swaggard/version.rb +5 -0
- data/spec/fixtures/api.json +1 -0
- data/spec/fixtures/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/fixtures/dummy/app/controllers/pets_controller.rb +15 -0
- data/spec/fixtures/dummy/config/application.rb +15 -0
- data/spec/fixtures/dummy/config/environments/development.rb +5 -0
- data/spec/fixtures/dummy/config/routes.rb +5 -0
- data/spec/fixtures/dummy/log/development.log +0 -0
- data/spec/integration/swaggard_spec.rb +19 -0
- data/spec/spec_helper.rb +27 -0
- metadata +210 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Swaggard
|
|
2
|
+
module Parsers
|
|
3
|
+
class Routes
|
|
4
|
+
|
|
5
|
+
def run(routes)
|
|
6
|
+
return {} unless routes
|
|
7
|
+
|
|
8
|
+
parsed_routes = {}
|
|
9
|
+
|
|
10
|
+
routes.each do |route|
|
|
11
|
+
controller = route_controller(route)
|
|
12
|
+
action = route_action(route)
|
|
13
|
+
|
|
14
|
+
parsed_routes[controller] ||= {}
|
|
15
|
+
parsed_routes[controller][action] = {
|
|
16
|
+
verb: route_verb(route),
|
|
17
|
+
path: route_path(route),
|
|
18
|
+
path_params: route_path_params(route)
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
parsed_routes
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def route_controller(route)
|
|
28
|
+
route.requirements[:controller]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def route_action(route)
|
|
32
|
+
route.requirements[:action]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def route_verb(route)
|
|
36
|
+
route.verb.source.gsub(/[$^]/, '')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def route_path(route)
|
|
40
|
+
path = route.path.spec.to_s
|
|
41
|
+
|
|
42
|
+
path.gsub!('(.:format)', '')
|
|
43
|
+
route.required_parts.each { |part| path.gsub!(":#{part}", "{#{part}}") }
|
|
44
|
+
|
|
45
|
+
path
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def route_path_params(route)
|
|
49
|
+
route.required_parts
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Swaggard
|
|
2
|
+
module Swagger
|
|
3
|
+
class Definition
|
|
4
|
+
|
|
5
|
+
attr_reader :id
|
|
6
|
+
|
|
7
|
+
def initialize(id)
|
|
8
|
+
@id = id
|
|
9
|
+
@properties = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_property(property)
|
|
13
|
+
@properties << property
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_doc
|
|
17
|
+
{
|
|
18
|
+
'properties' => Hash[@properties.map { |property| [property.id, property.to_doc] }]
|
|
19
|
+
}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require_relative 'parameters/body'
|
|
2
|
+
require_relative 'parameters/form'
|
|
3
|
+
require_relative 'parameters/list'
|
|
4
|
+
require_relative 'parameters/path'
|
|
5
|
+
require_relative 'parameters/query'
|
|
6
|
+
|
|
7
|
+
require_relative 'response'
|
|
8
|
+
|
|
9
|
+
module Swaggard
|
|
10
|
+
module Swagger
|
|
11
|
+
class Operation
|
|
12
|
+
|
|
13
|
+
attr_reader :nickname
|
|
14
|
+
attr_accessor :path, :parameters, :description, :http_method, :summary, :notes,
|
|
15
|
+
:error_responses, :tag
|
|
16
|
+
|
|
17
|
+
def initialize(yard_object, tag, routes)
|
|
18
|
+
@name = yard_object.name
|
|
19
|
+
@tag = tag
|
|
20
|
+
@summary = yard_object.docstring.lines.first || ''
|
|
21
|
+
@parameters = []
|
|
22
|
+
@responses = []
|
|
23
|
+
@description = (yard_object.docstring.lines[1..-1] || []).join("\n")
|
|
24
|
+
@formats = Swaggard.configuration.api_formats
|
|
25
|
+
|
|
26
|
+
yard_object.tags.each do |yard_tag|
|
|
27
|
+
value = yard_tag.text
|
|
28
|
+
|
|
29
|
+
case yard_tag.tag_name
|
|
30
|
+
when 'query_parameter'
|
|
31
|
+
@parameters << Parameters::Query.new(value)
|
|
32
|
+
when 'form_parameter'
|
|
33
|
+
@parameters << Parameters::Form.new(value)
|
|
34
|
+
when 'body_parameter'
|
|
35
|
+
body_parameter.add_property(value)
|
|
36
|
+
when 'parameter_list'
|
|
37
|
+
@parameters << Parameters::List.new(value)
|
|
38
|
+
when 'response_class'
|
|
39
|
+
@responses << Response.new(200, value)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
build_path_parameters(routes)
|
|
44
|
+
|
|
45
|
+
@parameters.sort_by { |parameter| parameter.name }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def valid?
|
|
49
|
+
@path.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_doc
|
|
53
|
+
produces = @formats.map { |format| "application/#{format}" }
|
|
54
|
+
consumes = @formats.map { |format| "application/#{format}" }
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
'tags' => [@tag.name],
|
|
58
|
+
'summary' => @summary,
|
|
59
|
+
'description' => @description,
|
|
60
|
+
'operationId' => @name,
|
|
61
|
+
'consumes' => consumes,
|
|
62
|
+
'produces' => produces,
|
|
63
|
+
'parameters' => @parameters.map(&:to_doc),
|
|
64
|
+
'responses' => Hash[@responses.map { |response| [response.status_code, response.to_doc] }]
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def definitions
|
|
69
|
+
@body_parameter ? [@body_parameter.definition] : []
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def body_parameter
|
|
75
|
+
return @body_parameter if @body_parameter
|
|
76
|
+
|
|
77
|
+
@body_parameter = Parameters::Body.new("#{@tag.controller_class.to_s}.#{@name}")
|
|
78
|
+
@parameters << @body_parameter
|
|
79
|
+
|
|
80
|
+
@body_parameter
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def build_path_parameters(routes)
|
|
84
|
+
return unless @tag.controller_class
|
|
85
|
+
|
|
86
|
+
route = (routes[@tag.controller_class.controller_path] || {})[@name.to_s]
|
|
87
|
+
|
|
88
|
+
return unless route
|
|
89
|
+
|
|
90
|
+
@http_method = route[:verb]
|
|
91
|
+
@path = route[:path]
|
|
92
|
+
|
|
93
|
+
route[:path_params].each { |path_param| @parameters << Parameters::Path.new(path_param) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Swaggard
|
|
2
|
+
module Swagger
|
|
3
|
+
module Parameters
|
|
4
|
+
class Base
|
|
5
|
+
|
|
6
|
+
attr_reader :name
|
|
7
|
+
|
|
8
|
+
def to_doc
|
|
9
|
+
{
|
|
10
|
+
'in' => @in,
|
|
11
|
+
'name' => @name,
|
|
12
|
+
'description' => @description,
|
|
13
|
+
'required' => @is_required,
|
|
14
|
+
'type' => @data_type
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
require_relative '../type'
|
|
3
|
+
|
|
4
|
+
module Swaggard
|
|
5
|
+
module Swagger
|
|
6
|
+
module Parameters
|
|
7
|
+
class Body < Base
|
|
8
|
+
|
|
9
|
+
attr_reader :definition
|
|
10
|
+
|
|
11
|
+
def initialize(operation_name)
|
|
12
|
+
@in = 'body'
|
|
13
|
+
@name = 'body'
|
|
14
|
+
@description = ''
|
|
15
|
+
@definition = Definition.new("#{operation_name}_body")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def add_property(string)
|
|
19
|
+
property = Property.new(string)
|
|
20
|
+
@definition.add_property(property)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_doc
|
|
24
|
+
doc = super
|
|
25
|
+
|
|
26
|
+
doc.delete('type')
|
|
27
|
+
|
|
28
|
+
doc['required'] = false
|
|
29
|
+
doc['schema'] = { '$ref' => "#/definitions/#{@definition.id}" }
|
|
30
|
+
|
|
31
|
+
doc
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Property
|
|
38
|
+
|
|
39
|
+
attr_reader :id
|
|
40
|
+
|
|
41
|
+
def initialize(string)
|
|
42
|
+
parse(string)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_doc
|
|
46
|
+
result = @type.to_doc
|
|
47
|
+
result['description'] = @description if @description
|
|
48
|
+
result
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Example: [Array] status Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
52
|
+
# Example: [Array] status(required) Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
53
|
+
# Example: [Integer] media[media_type_id] ID of the desired media type.
|
|
54
|
+
def parse(string)
|
|
55
|
+
data_type, name, required, description = string.match(/\A\[(\w*)\]\s*([\w\[\]]*)(\(required\))?\s*(.*)\Z/).captures
|
|
56
|
+
|
|
57
|
+
@id = name
|
|
58
|
+
@description = description
|
|
59
|
+
@type = Type.new([data_type.downcase])
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
module Parameters
|
|
6
|
+
class Form < Base
|
|
7
|
+
|
|
8
|
+
def initialize(string)
|
|
9
|
+
@in = 'formData'
|
|
10
|
+
parse(string)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# Example: [Array] status Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
16
|
+
# Example: [Array] status(required) Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
17
|
+
# Example: [Integer] media[media_type_id] ID of the desired media type.
|
|
18
|
+
def parse(string)
|
|
19
|
+
data_type, name, required, description = string.match(/\A\[(\w*)\]\s*([\w\[\]]*)(\(required\))?\s*(.*)\Z/).captures
|
|
20
|
+
allow_multiple = name.gsub!('[]', '')
|
|
21
|
+
|
|
22
|
+
@name = name
|
|
23
|
+
@description = description
|
|
24
|
+
@data_type = data_type.downcase
|
|
25
|
+
@is_required = required.present?
|
|
26
|
+
@allow_multiple = allow_multiple.present?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
module Parameters
|
|
6
|
+
class List < Base
|
|
7
|
+
|
|
8
|
+
def initialize(string)
|
|
9
|
+
@in = 'query'
|
|
10
|
+
parse(string)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def to_doc
|
|
14
|
+
doc = super
|
|
15
|
+
|
|
16
|
+
doc.merge(
|
|
17
|
+
{
|
|
18
|
+
'type' => 'array',
|
|
19
|
+
'items' => { 'type' => @data_type },
|
|
20
|
+
'enum' => @list_values
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# Example: [String] sort_order Orders ownerships by fields. (e.g. sort_order=created_at)
|
|
28
|
+
# [List] id
|
|
29
|
+
# [List] begin_at
|
|
30
|
+
# [List] end_at
|
|
31
|
+
# [List] created_at
|
|
32
|
+
def parse(string)
|
|
33
|
+
data_type, name, required, description, set_string = string.match(/\A\[(\w*)\]\s*(\w*)(\(required\))?\s*(.*)\n([.\s\S]*)\Z/).captures
|
|
34
|
+
|
|
35
|
+
@list_values = set_string.split('[List]').map(&:strip).reject { |string| string.empty? }
|
|
36
|
+
|
|
37
|
+
@name = name
|
|
38
|
+
@description = description
|
|
39
|
+
@data_type = data_type.downcase
|
|
40
|
+
@is_required = required.present?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
module Parameters
|
|
6
|
+
class Path < Base
|
|
7
|
+
|
|
8
|
+
attr_reader :name
|
|
9
|
+
|
|
10
|
+
def initialize(param_name)
|
|
11
|
+
@in = 'path'
|
|
12
|
+
@name = param_name.to_s
|
|
13
|
+
@data_type = 'string'
|
|
14
|
+
@is_required = true
|
|
15
|
+
@description = "Scope response to #{@name}"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
module Parameters
|
|
6
|
+
class Query < Base
|
|
7
|
+
|
|
8
|
+
def initialize(string)
|
|
9
|
+
@in = 'query'
|
|
10
|
+
parse(string)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# Example: [Array] status Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
16
|
+
# Example: [Array] status(required) Filter by status. (e.g. status[]=1&status[]=2&status[]=3)
|
|
17
|
+
# Example: [Integer] media[media_type_id] ID of the desired media type.
|
|
18
|
+
def parse(string)
|
|
19
|
+
data_type, name, required, description = string.match(/\A\[(\w*)\]\s*([\w\[\]]*)(\(required\))?\s*(.*)\Z/).captures
|
|
20
|
+
allow_multiple = name.gsub!('[]', '')
|
|
21
|
+
|
|
22
|
+
@name = name
|
|
23
|
+
@description = description
|
|
24
|
+
@data_type = data_type.downcase
|
|
25
|
+
@is_required = required.present?
|
|
26
|
+
@allow_multiple = allow_multiple.present?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative 'operation'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
class Path
|
|
6
|
+
|
|
7
|
+
attr_reader :path
|
|
8
|
+
|
|
9
|
+
def initialize(path)
|
|
10
|
+
@path = path
|
|
11
|
+
@operations = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def add_operation(operation)
|
|
15
|
+
@operations[operation.http_method.downcase] = operation
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_doc
|
|
19
|
+
Hash[@operations.map { |http_method, operation| [http_method, operation.to_doc] }]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'type'
|
|
2
|
+
|
|
3
|
+
module Swaggard
|
|
4
|
+
module Swagger
|
|
5
|
+
class Property
|
|
6
|
+
|
|
7
|
+
attr_reader :id, :type, :description
|
|
8
|
+
|
|
9
|
+
def initialize(yard_object)
|
|
10
|
+
@id = yard_object.name
|
|
11
|
+
@type = Type.new(yard_object.types)
|
|
12
|
+
@description = yard_object.text
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_doc
|
|
16
|
+
result = @type.to_doc
|
|
17
|
+
result['description'] = @description if @description
|
|
18
|
+
result
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|