brainstem 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +77 -0
  3. data/README.md +119 -0
  4. data/docs/api_doc_generator.markdown +45 -4
  5. data/docs/brainstem_executable.markdown +1 -1
  6. data/docs/oas_2_docgen.png +0 -0
  7. data/docs/oas_2_docgen_ascii.txt +78 -0
  8. data/lib/brainstem/api_docs.rb +23 -9
  9. data/lib/brainstem/api_docs/abstract_collection.rb +0 -13
  10. data/lib/brainstem/api_docs/atlas.rb +0 -14
  11. data/lib/brainstem/api_docs/builder.rb +0 -14
  12. data/lib/brainstem/api_docs/controller.rb +7 -16
  13. data/lib/brainstem/api_docs/controller_collection.rb +0 -3
  14. data/lib/brainstem/api_docs/endpoint.rb +73 -19
  15. data/lib/brainstem/api_docs/endpoint_collection.rb +0 -7
  16. data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +0 -2
  17. data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +1 -9
  18. data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +1 -9
  19. data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +39 -24
  20. data/lib/brainstem/api_docs/formatters/markdown/helper.rb +0 -13
  21. data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +22 -35
  22. data/lib/brainstem/api_docs/formatters/open_api_specification/helper.rb +66 -0
  23. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/controller_formatter.rb +57 -0
  24. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter.rb +311 -0
  25. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter.rb +197 -0
  26. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_collection_formatter.rb +60 -0
  27. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_formatter.rb +162 -0
  28. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/info_formatter.rb +126 -0
  29. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter.rb +132 -0
  30. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/security_definitions_formatter.rb +99 -0
  31. data/lib/brainstem/api_docs/formatters/open_api_specification/version_2/tags_formatter.rb +123 -0
  32. data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +0 -7
  33. data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +1 -20
  34. data/lib/brainstem/api_docs/presenter.rb +21 -27
  35. data/lib/brainstem/api_docs/presenter_collection.rb +1 -11
  36. data/lib/brainstem/api_docs/resolver.rb +1 -8
  37. data/lib/brainstem/api_docs/sinks/abstract_sink.rb +0 -4
  38. data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +0 -9
  39. data/lib/brainstem/api_docs/sinks/open_api_specification_sink.rb +234 -0
  40. data/lib/brainstem/api_docs/sinks/stdout_sink.rb +0 -5
  41. data/lib/brainstem/cli.rb +0 -13
  42. data/lib/brainstem/cli/abstract_command.rb +0 -7
  43. data/lib/brainstem/cli/generate_api_docs_command.rb +48 -24
  44. data/lib/brainstem/concerns/controller_dsl.rb +288 -145
  45. data/lib/brainstem/concerns/formattable.rb +0 -5
  46. data/lib/brainstem/concerns/optional.rb +0 -1
  47. data/lib/brainstem/concerns/presenter_dsl.rb +2 -21
  48. data/lib/brainstem/dsl/configuration.rb +0 -11
  49. data/lib/brainstem/presenter.rb +0 -4
  50. data/lib/brainstem/version.rb +1 -1
  51. data/spec/brainstem/api_docs/abstract_collection_spec.rb +0 -11
  52. data/spec/brainstem/api_docs/atlas_spec.rb +0 -6
  53. data/spec/brainstem/api_docs/builder_spec.rb +0 -4
  54. data/spec/brainstem/api_docs/controller_collection_spec.rb +0 -2
  55. data/spec/brainstem/api_docs/controller_spec.rb +29 -18
  56. data/spec/brainstem/api_docs/endpoint_collection_spec.rb +0 -6
  57. data/spec/brainstem/api_docs/endpoint_spec.rb +343 -13
  58. data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +0 -2
  59. data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +0 -1
  60. data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +0 -5
  61. data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +94 -8
  62. data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +0 -8
  63. data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +0 -7
  64. data/spec/brainstem/api_docs/formatters/open_api_specification/helper_spec.rb +210 -0
  65. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/controller_formatter_spec.rb +81 -0
  66. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter_spec.rb +672 -0
  67. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter_spec.rb +335 -0
  68. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_collection_formatter_spec.rb +59 -0
  69. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/endpoint_formatter_spec.rb +308 -0
  70. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/info_formatter_spec.rb +89 -0
  71. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/presenter_formatter_spec.rb +430 -0
  72. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/security_definitions_formatter_spec.rb +190 -0
  73. data/spec/brainstem/api_docs/formatters/open_api_specification/version_2/tags_formatter_spec.rb +217 -0
  74. data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +0 -2
  75. data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +0 -2
  76. data/spec/brainstem/api_docs/presenter_collection_spec.rb +0 -2
  77. data/spec/brainstem/api_docs/presenter_spec.rb +58 -18
  78. data/spec/brainstem/api_docs/resolver_spec.rb +0 -1
  79. data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +0 -2
  80. data/spec/brainstem/api_docs/sinks/open_api_specification_sink_spec.rb +371 -0
  81. data/spec/brainstem/api_docs_spec.rb +2 -0
  82. data/spec/brainstem/cli/abstract_command_spec.rb +0 -4
  83. data/spec/brainstem/cli/generate_api_docs_command_spec.rb +53 -2
  84. data/spec/brainstem/concerns/controller_dsl_spec.rb +430 -64
  85. data/spec/brainstem/concerns/presenter_dsl_spec.rb +0 -20
  86. data/spec/brainstem/preloader_spec.rb +0 -7
  87. data/spec/brainstem/presenter_spec.rb +0 -1
  88. data/spec/dummy/rails.rb +0 -1
  89. data/spec/spec_helpers/db.rb +0 -1
  90. metadata +37 -2
@@ -0,0 +1,60 @@
1
+ require 'brainstem/api_docs/formatters/abstract_formatter'
2
+
3
+ #
4
+ # Responsible for formatting each endpoint.
5
+ #
6
+ module Brainstem
7
+ module ApiDocs
8
+ module Formatters
9
+ module OpenApiSpecification
10
+ module Version2
11
+ class EndpointCollectionFormatter < AbstractFormatter
12
+
13
+ attr_accessor :endpoint_collection,
14
+ :output
15
+
16
+ def initialize(endpoint_collection, options = {})
17
+ self.endpoint_collection = endpoint_collection
18
+ self.output = {}
19
+
20
+ super options
21
+ end
22
+
23
+ def call
24
+ format_endpoints!
25
+ end
26
+
27
+ #####################################################################
28
+ private
29
+ #####################################################################
30
+
31
+ def documentable_endpoints
32
+ endpoint_collection
33
+ .only_documentable
34
+ end
35
+
36
+ def format_endpoints!
37
+ documentable_endpoints.each do |endpoint|
38
+ formatted_endpoint = endpoint.formatted_as(:oas_v2)
39
+ next if formatted_endpoint.blank?
40
+
41
+ if (common_keys = output.keys & formatted_endpoint.keys).present?
42
+ common_keys.each do |key|
43
+ output[key].merge!(formatted_endpoint[key])
44
+ end
45
+ else
46
+ output.merge!(formatted_endpoint)
47
+ end
48
+ end
49
+
50
+ output
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ Brainstem::ApiDocs::FORMATTERS[:endpoint_collection][:oas_v2] =
60
+ Brainstem::ApiDocs::Formatters::OpenApiSpecification::Version2::EndpointCollectionFormatter.method(:call)
@@ -0,0 +1,162 @@
1
+ require 'active_support/core_ext/hash/except'
2
+ require 'forwardable'
3
+ require 'brainstem/api_docs/formatters/abstract_formatter'
4
+ require 'brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/param_definitions_formatter'
5
+ require 'brainstem/api_docs/formatters/open_api_specification/version_2/endpoint/response_definitions_formatter'
6
+ require 'brainstem/api_docs/formatters/open_api_specification/helper'
7
+
8
+ #
9
+ # Responsible for formatting each endpoint.
10
+ #
11
+ module Brainstem
12
+ module ApiDocs
13
+ module Formatters
14
+ module OpenApiSpecification
15
+ module Version2
16
+ class EndpointFormatter < AbstractFormatter
17
+ include Helper
18
+ extend Forwardable
19
+
20
+ attr_accessor :endpoint,
21
+ :presenter,
22
+ :endpoint_key,
23
+ :http_method,
24
+ :output
25
+
26
+ def initialize(endpoint, options = {})
27
+ self.endpoint = endpoint
28
+ self.presenter = endpoint.presenter
29
+ self.endpoint_key = formatted_url
30
+ self.http_method = format_http_method(endpoint)
31
+ self.output = { endpoint_key => { http_method => {} } }.with_indifferent_access
32
+
33
+ super options
34
+ end
35
+
36
+ def call
37
+ return {} if endpoint.nodoc?
38
+
39
+ format_summary!
40
+ format_optional_info!
41
+ format_security!
42
+ format_tags!
43
+ format_parameters!
44
+ format_response!
45
+
46
+ output
47
+ end
48
+
49
+ ################################################################################
50
+ private
51
+ ################################################################################
52
+
53
+ delegate :controller => :endpoint
54
+
55
+ ################################################################################
56
+ # Methods to override
57
+ ################################################################################
58
+
59
+ #
60
+ # Format the endpoint summary
61
+ #
62
+ def summary
63
+ endpoint.title
64
+ end
65
+
66
+ #
67
+ # Format the endpoint description
68
+ #
69
+ def description
70
+ endpoint.description
71
+ end
72
+
73
+ #
74
+ # Formats the actual URI
75
+ #
76
+ def formatted_url
77
+ endpoint.path
78
+ .gsub('(.:format)', '')
79
+ .gsub(/(:(?<param>\w+))/, '{\k<param>}')
80
+ .gsub(Brainstem::ApiDocs.base_path, '')
81
+ end
82
+
83
+ ################################################################################
84
+ # Avoid overridding
85
+ ################################################################################
86
+
87
+ #
88
+ # Formats the summary as given, falling back to the humanized action
89
+ # name.
90
+ #
91
+ def format_summary!
92
+ output[endpoint_key][http_method].merge! summary: summary.to_s.strip
93
+ end
94
+
95
+ #
96
+ # Adds the following properties.
97
+ # - description
98
+ # - operation_id
99
+ # - consumes
100
+ # - produces
101
+ # - schemes
102
+ # - external_docs
103
+ # - deprecated
104
+ #
105
+ def format_optional_info!
106
+ info = {
107
+ description: format_description(description),
108
+ operation_id: endpoint.operation_id,
109
+ consumes: endpoint.consumes,
110
+ produces: endpoint.produces,
111
+ schemes: endpoint.schemes,
112
+ external_docs: endpoint.external_docs,
113
+ deprecated: endpoint.deprecated,
114
+ }.reject { |_,v| v.blank? }
115
+
116
+ output[endpoint_key][http_method].merge!(info)
117
+ end
118
+
119
+ #
120
+ # Adds the security schemes for the given endpoint.
121
+ #
122
+ def format_security!
123
+ return if endpoint.security.nil?
124
+
125
+ output[endpoint_key][http_method].merge! security: endpoint.security
126
+ end
127
+
128
+ #
129
+ # Adds the tags for the given endpoint.
130
+ #
131
+ def format_tags!
132
+ tag_name = endpoint.controller.tag || format_tag_name(endpoint.controller.name)
133
+
134
+ output[endpoint_key][http_method].merge! tags: [tag_name]
135
+ end
136
+
137
+ #
138
+ # Formats each parameter.
139
+ #
140
+ def format_parameters!
141
+ output[endpoint_key][http_method].merge!(
142
+ parameters: ::Brainstem::ApiDocs::FORMATTERS[:parameters][:oas_v2].call(endpoint)
143
+ )
144
+ end
145
+
146
+ #
147
+ # Formats the response.
148
+ #
149
+ def format_response!
150
+ output[endpoint_key][http_method].merge!(
151
+ responses: ::Brainstem::ApiDocs::FORMATTERS[:response][:oas_v2].call(endpoint)
152
+ )
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ Brainstem::ApiDocs::FORMATTERS[:endpoint][:oas_v2] =
162
+ Brainstem::ApiDocs::Formatters::OpenApiSpecification::Version2::EndpointFormatter.method(:call)
@@ -0,0 +1,126 @@
1
+ require 'brainstem/api_docs/formatters/abstract_formatter'
2
+
3
+ module Brainstem
4
+ module ApiDocs
5
+ module Formatters
6
+ module OpenApiSpecification
7
+ module Version2
8
+ class InfoFormatter < AbstractFormatter
9
+
10
+ #
11
+ # Declares the options that are permissable to set on this instance.
12
+ #
13
+ def valid_options
14
+ super | [
15
+ :version
16
+ ]
17
+ end
18
+
19
+ attr_accessor :output,
20
+ :version
21
+
22
+ def initialize(options = {})
23
+ self.output = ActiveSupport::HashWithIndifferentAccess.new
24
+
25
+ super options
26
+ end
27
+
28
+ def call
29
+ format_swagger_object!
30
+ format_info_object!
31
+ output
32
+ end
33
+
34
+ #####################################################################
35
+ private
36
+ #####################################################################
37
+
38
+ def format_swagger_object!
39
+ output.merge!( swagger_object )
40
+ end
41
+
42
+ def format_info_object!
43
+ output.merge!( 'info' => info_object )
44
+ end
45
+
46
+ def swagger_object
47
+ {
48
+ 'swagger' => '2.0',
49
+ 'host' => host,
50
+ 'basePath' => Brainstem::ApiDocs.base_path,
51
+ 'schemes' => schemes,
52
+ 'consumes' => consumes,
53
+ 'produces' => produces
54
+ }.with_indifferent_access.reject { |_, v| v.blank? }
55
+ end
56
+
57
+ def info_object
58
+ {
59
+ 'version' => version.presence || '1.0',
60
+ 'title' => title,
61
+ 'description' => description,
62
+ 'termsOfService' => terms_of_service,
63
+ 'contact' => contact_object,
64
+ 'license' => license_object
65
+ }.with_indifferent_access.reject { |_, v| v.blank? }
66
+ end
67
+
68
+ #####################################################################
69
+ # Override with custom values #
70
+ #####################################################################
71
+
72
+ def host
73
+ 'petstore.swagger.io'
74
+ end
75
+
76
+ def schemes
77
+ %w(https)
78
+ end
79
+
80
+ def consumes
81
+ %w(application/json)
82
+ end
83
+
84
+ def produces
85
+ %w(application/json)
86
+ end
87
+
88
+ def title
89
+ 'Petstore'
90
+ end
91
+
92
+ def description
93
+ <<-DESC.strip_heredoc
94
+ This is a sample server Petstore server. You can find out more about Swagger at
95
+ [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).
96
+ For this sample, you can use the api key `special-key` to test the authorization filters.
97
+ DESC
98
+ end
99
+
100
+ def terms_of_service
101
+ 'http://swagger.io/terms/'
102
+ end
103
+
104
+ def contact_object
105
+ {
106
+ 'name' => 'Pet Store Support',
107
+ 'url' => 'https://swagger.io/support/',
108
+ 'email' => 'apiteam@swagger.io',
109
+ }
110
+ end
111
+
112
+ def license_object
113
+ {
114
+ 'name' => 'MIT',
115
+ 'url' => 'https://opensource.org/licenses/MIT',
116
+ }
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ Brainstem::ApiDocs::FORMATTERS[:info][:oas_v2] =
126
+ Brainstem::ApiDocs::Formatters::OpenApiSpecification::Version2::InfoFormatter.method(:call)
@@ -0,0 +1,132 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'brainstem/api_docs/formatters/abstract_formatter'
3
+ require 'brainstem/api_docs/formatters/open_api_specification/helper'
4
+
5
+ module Brainstem
6
+ module ApiDocs
7
+ module Formatters
8
+ module OpenApiSpecification
9
+ module Version2
10
+ class PresenterFormatter < AbstractFormatter
11
+ include Helper
12
+
13
+ def initialize(presenter, options = {})
14
+ self.presenter = presenter
15
+ self.definition = ActiveSupport::HashWithIndifferentAccess.new
16
+ self.output = ActiveSupport::HashWithIndifferentAccess.new
17
+
18
+ super options
19
+ end
20
+
21
+ attr_accessor :presenter,
22
+ :output,
23
+ :definition,
24
+ :presented_class
25
+
26
+ def call
27
+ return {} if presenter.nodoc?
28
+
29
+ format_title!
30
+ format_description!
31
+ format_type!
32
+ format_fields!
33
+
34
+ output.merge!(presenter.target_class => definition.reject {|_, v| v.blank?})
35
+ end
36
+
37
+ #####################################################################
38
+ private
39
+ #####################################################################
40
+
41
+ def format_title!
42
+ definition.merge! title: presenter_title(presenter)
43
+ end
44
+
45
+ def format_description!
46
+ definition.merge! description: format_description(presenter.description)
47
+ end
48
+
49
+ def format_type!
50
+ definition.merge! type: 'object'
51
+ end
52
+
53
+ def format_fields!
54
+ return unless presenter.valid_fields.any?
55
+
56
+ definition.merge! properties: format_field_branch(presenter.valid_fields)
57
+ end
58
+
59
+ def format_field_branch(branch)
60
+ branch.inject(ActiveSupport::HashWithIndifferentAccess.new) do |buffer, (name, field)|
61
+ if nested_field?(field)
62
+ buffer[name.to_s] = case field.type
63
+ when 'hash'
64
+ {
65
+ type: 'object',
66
+ properties: format_field_branch(field.to_h)
67
+ }.with_indifferent_access
68
+ when 'array'
69
+ {
70
+ type: 'array',
71
+ items: {
72
+ type: 'object',
73
+ properties: format_field_branch(field.to_h)
74
+ }
75
+ }.with_indifferent_access
76
+ else
77
+ raise "Unknown Brainstem Field type encountered(#{field.type}) for field #{name}"
78
+ end
79
+ else
80
+ buffer[name.to_s] = format_field_leaf(field)
81
+ end
82
+
83
+ buffer
84
+ end
85
+ end
86
+
87
+ def nested_field?(field)
88
+ field.respond_to?(:configuration)
89
+ end
90
+
91
+ def format_field_leaf(field)
92
+ field_data = type_and_format(field.type, field.options[:item_type])
93
+
94
+ unless field_data
95
+ raise "Unknown Brainstem Field type encountered(#{field.type}) for field #{field.name}"
96
+ end
97
+
98
+ field_data.merge!(description: format_description_for(field))
99
+ field_data.delete(:description) if field_data[:description].blank?
100
+
101
+ field_data
102
+ end
103
+
104
+ def format_description_for(field)
105
+ field_description = format_description(field.description) || ''
106
+ field_description << format_conditional_description(field.options)
107
+ field_description << "\nOnly returned when requested through the optional_fields param.\n" if field.optional?
108
+ field_description.try(:chomp!)
109
+ field_description
110
+ end
111
+
112
+ def format_conditional_description(field_options)
113
+ return '' if field_options[:if].blank?
114
+
115
+ conditions = field_options[:if]
116
+ .reject { |cond| presenter.conditionals[cond].options[:nodoc] }
117
+ .map { |cond| uncapitalize(presenter.conditionals[cond].description) }
118
+ .delete_if(&:empty?)
119
+ .uniq
120
+ .to_sentence
121
+
122
+ conditions.present? ? "\nVisible when #{conditions}.\n" : ''
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ Brainstem::ApiDocs::FORMATTERS[:presenter][:oas_v2] =
132
+ Brainstem::ApiDocs::Formatters::OpenApiSpecification::Version2::PresenterFormatter.method(:call)