swaggard 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +178 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.eot +0 -0
  6. data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.svg +411 -0
  7. data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.ttf +0 -0
  8. data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.woff +0 -0
  9. data/app/assets/fonts/swaggard/droid-sans-v6-latin-700.woff2 +0 -0
  10. data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.eot +0 -0
  11. data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.svg +403 -0
  12. data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.ttf +0 -0
  13. data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.woff +0 -0
  14. data/app/assets/fonts/swaggard/droid-sans-v6-latin-regular.woff2 +0 -0
  15. data/app/assets/images/swaggard/logo_small.png +0 -0
  16. data/app/assets/images/swaggard/pet_store_api.png +0 -0
  17. data/app/assets/images/swaggard/throbber.gif +0 -0
  18. data/app/assets/images/swaggard/wordnik_api.png +0 -0
  19. data/app/assets/javascripts/swaggard/application.js +24 -0
  20. data/app/assets/javascripts/swaggard/lib/MD5.js +319 -0
  21. data/app/assets/javascripts/swaggard/lib/backbone-min.js +15 -0
  22. data/app/assets/javascripts/swaggard/lib/handlebars-1.0.rc.1.js +1920 -0
  23. data/app/assets/javascripts/swaggard/lib/handlebars-2.0.0.js +28 -0
  24. data/app/assets/javascripts/swaggard/lib/highlight.7.3.pack.js +1 -0
  25. data/app/assets/javascripts/swaggard/lib/jquery-1.8.0.min.js +2 -0
  26. data/app/assets/javascripts/swaggard/lib/jquery.ba-bbq.min.js +18 -0
  27. data/app/assets/javascripts/swaggard/lib/jquery.slideto.min.js +1 -0
  28. data/app/assets/javascripts/swaggard/lib/jquery.wiggle.min.js +8 -0
  29. data/app/assets/javascripts/swaggard/lib/marked.js +1272 -0
  30. data/app/assets/javascripts/swaggard/lib/shred.bundle.js +2765 -0
  31. data/app/assets/javascripts/swaggard/lib/swagger-client.js +3294 -0
  32. data/app/assets/javascripts/swaggard/lib/swagger.js +794 -0
  33. data/app/assets/javascripts/swaggard/lib/underscore-min.js +32 -0
  34. data/app/assets/javascripts/swaggard/swagger-ui.js +2240 -0
  35. data/app/assets/javascripts/swaggard/swagger-ui_org.js +2005 -0
  36. data/app/assets/stylesheets/swaggard/application.css +16 -0
  37. data/app/assets/stylesheets/swaggard/reset.css +125 -0
  38. data/app/assets/stylesheets/swaggard/screen.css.scss +1256 -0
  39. data/app/assets/stylesheets/swaggard/typography.css.scss +26 -0
  40. data/app/controllers/swaggard/application_controller.rb +4 -0
  41. data/app/controllers/swaggard/swagger_controller.rb +21 -0
  42. data/app/views/swaggard/swagger/index.html.erb +74 -0
  43. data/config/routes.rb +3 -0
  44. data/lib/swaggard.rb +92 -0
  45. data/lib/swaggard/api_definition.rb +52 -0
  46. data/lib/swaggard/configuration.rb +82 -0
  47. data/lib/swaggard/engine.rb +18 -0
  48. data/lib/swaggard/parsers/controllers.rb +30 -0
  49. data/lib/swaggard/parsers/models.rb +29 -0
  50. data/lib/swaggard/parsers/routes.rb +54 -0
  51. data/lib/swaggard/swagger/definition.rb +24 -0
  52. data/lib/swaggard/swagger/operation.rb +98 -0
  53. data/lib/swaggard/swagger/parameters/base.rb +21 -0
  54. data/lib/swaggard/swagger/parameters/body.rb +67 -0
  55. data/lib/swaggard/swagger/parameters/form.rb +32 -0
  56. data/lib/swaggard/swagger/parameters/list.rb +46 -0
  57. data/lib/swaggard/swagger/parameters/path.rb +21 -0
  58. data/lib/swaggard/swagger/parameters/query.rb +32 -0
  59. data/lib/swaggard/swagger/path.rb +24 -0
  60. data/lib/swaggard/swagger/property.rb +23 -0
  61. data/lib/swaggard/swagger/response.rb +45 -0
  62. data/lib/swaggard/swagger/tag.rb +28 -0
  63. data/lib/swaggard/swagger/type.rb +72 -0
  64. data/lib/swaggard/version.rb +5 -0
  65. data/spec/fixtures/api.json +1 -0
  66. data/spec/fixtures/dummy/app/controllers/application_controller.rb +2 -0
  67. data/spec/fixtures/dummy/app/controllers/pets_controller.rb +15 -0
  68. data/spec/fixtures/dummy/config/application.rb +15 -0
  69. data/spec/fixtures/dummy/config/environments/development.rb +5 -0
  70. data/spec/fixtures/dummy/config/routes.rb +5 -0
  71. data/spec/fixtures/dummy/log/development.log +0 -0
  72. data/spec/integration/swaggard_spec.rb +19 -0
  73. data/spec/spec_helper.rb +27 -0
  74. 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