brainstem 1.4.1 → 2.0.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 (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)