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
@@ -7,7 +7,6 @@ module Brainstem
7
7
  class EndpointCollection < AbstractCollection
8
8
  include Concerns::Formattable
9
9
 
10
-
11
10
  def find_from_route(route)
12
11
  find do |endpoint|
13
12
  endpoint.path == route[:path] &&
@@ -18,7 +17,6 @@ module Brainstem
18
17
 
19
18
  alias_method :find_by_route, :find_from_route
20
19
 
21
-
22
20
  def create_from_route(route, controller)
23
21
  Endpoint.new(atlas) do |ep|
24
22
  ep.path = route[:path]
@@ -29,27 +27,22 @@ module Brainstem
29
27
  end.tap { |endpoint| self.<< endpoint }
30
28
  end
31
29
 
32
-
33
30
  def only_documentable
34
31
  self.class.with_members(atlas, reject(&:nodoc?))
35
32
  end
36
33
 
37
-
38
34
  def with_declared_presented_class
39
35
  self.class.with_members(atlas, reject { |m| m.declared_presented_class.nil? })
40
36
  end
41
37
 
42
-
43
38
  def sorted
44
39
  self.class.with_members(atlas, sort)
45
40
  end
46
41
 
47
-
48
42
  def with_actions_in_controller(const)
49
43
  self.class.with_members(atlas, reject { |m| !const.method_defined?(m.action) })
50
44
  end
51
45
 
52
-
53
46
  def sorted_with_actions_in_controller(const)
54
47
  with_actions_in_controller(const).sorted
55
48
  end
@@ -46,12 +46,10 @@ module Brainstem
46
46
  new(*args).call
47
47
  end
48
48
 
49
-
50
49
  def initialize(*args)
51
50
  super args.last || {}
52
51
  end
53
52
 
54
-
55
53
  #
56
54
  # Override to transform atlas data into serialized format.
57
55
  #
@@ -17,14 +17,12 @@ module Brainstem
17
17
  ]
18
18
  end
19
19
 
20
-
21
20
  attr_accessor :controller,
22
21
  :include_actions,
23
22
  :output
24
23
 
25
24
  alias_method :include_actions?, :include_actions
26
25
 
27
-
28
26
  def initialize(controller, options = {})
29
27
  self.controller = controller
30
28
  self.output = ""
@@ -32,7 +30,6 @@ module Brainstem
32
30
  super options
33
31
  end
34
32
 
35
-
36
33
  def call
37
34
  return output if controller.nodoc?
38
35
  format_title!
@@ -40,22 +37,18 @@ module Brainstem
40
37
  format_actions!
41
38
  end
42
39
 
43
-
44
40
  #####################################################################
45
41
  private
46
42
  #####################################################################
47
43
 
48
-
49
44
  def format_title!
50
45
  output << md_h2(controller.title)
51
46
  end
52
47
 
53
-
54
48
  def format_description!
55
49
  output << md_p(controller.description) unless controller.description.empty?
56
50
  end
57
51
 
58
-
59
52
  def format_actions!
60
53
  return unless include_actions?
61
54
 
@@ -71,6 +64,5 @@ module Brainstem
71
64
  end
72
65
  end
73
66
 
74
-
75
- Brainstem::ApiDocs::FORMATTERS[:controller][:markdown] = \
67
+ Brainstem::ApiDocs::FORMATTERS[:controller][:markdown] =
76
68
  Brainstem::ApiDocs::Formatters::Markdown::ControllerFormatter.method(:call)
@@ -23,24 +23,20 @@ module Brainstem
23
23
  super options
24
24
  end
25
25
 
26
-
27
26
  attr_accessor :endpoint_collection,
28
27
  :zero_text,
29
28
  :output
30
29
 
31
-
32
30
  def valid_options
33
31
  super | [ :zero_text ]
34
32
  end
35
33
 
36
-
37
34
  def call
38
35
  format_endpoints!
39
36
  format_zero_text! if output.empty?
40
37
  output
41
38
  end
42
39
 
43
-
44
40
  #####################################################################
45
41
  private
46
42
  #####################################################################
@@ -52,12 +48,10 @@ module Brainstem
52
48
  .reject(&:empty?)
53
49
  end
54
50
 
55
-
56
51
  def format_endpoints!
57
52
  output << all_formatted_endpoints.join(md_hr)
58
53
  end
59
54
 
60
-
61
55
  def format_zero_text!
62
56
  output << zero_text
63
57
  end
@@ -67,7 +61,5 @@ module Brainstem
67
61
  end
68
62
  end
69
63
 
70
-
71
-
72
- Brainstem::ApiDocs::FORMATTERS[:endpoint_collection][:markdown] = \
64
+ Brainstem::ApiDocs::FORMATTERS[:endpoint_collection][:markdown] =
73
65
  Brainstem::ApiDocs::Formatters::Markdown::EndpointCollectionFormatter.method(:call)
@@ -14,12 +14,10 @@ module Brainstem
14
14
  include Helper
15
15
  extend Forwardable
16
16
 
17
-
18
17
  ################################################################################
19
18
  # Public API
20
19
  ################################################################################
21
20
 
22
-
23
21
  def initialize(endpoint, options = {})
24
22
  self.endpoint = endpoint
25
23
  self.output = ""
@@ -27,11 +25,9 @@ module Brainstem
27
25
  super options
28
26
  end
29
27
 
30
-
31
28
  attr_accessor :endpoint,
32
29
  :output
33
30
 
34
-
35
31
  def call
36
32
  return output if endpoint.nodoc?
37
33
 
@@ -44,14 +40,12 @@ module Brainstem
44
40
  output
45
41
  end
46
42
 
47
-
48
43
  ################################################################################
49
44
  private
50
45
  ################################################################################
51
46
 
52
47
  delegate :controller => :endpoint
53
48
 
54
-
55
49
  #
56
50
  # Formats the title as given, falling back to the humanized action
57
51
  # name.
@@ -60,7 +54,6 @@ module Brainstem
60
54
  output << md_h4(endpoint.title)
61
55
  end
62
56
 
63
-
64
57
  #
65
58
  # Formats the description if given.
66
59
  #
@@ -68,7 +61,6 @@ module Brainstem
68
61
  output << md_p(endpoint.description) unless endpoint.description.empty?
69
62
  end
70
63
 
71
-
72
64
  #
73
65
  # Formats the actual URI and stated HTTP methods.
74
66
  #
@@ -78,7 +70,6 @@ module Brainstem
78
70
  output << md_code("#{http_methods} #{path}")
79
71
  end
80
72
 
81
-
82
73
  #
83
74
  # Formats each parameter.
84
75
  #
@@ -118,18 +109,15 @@ module Brainstem
118
109
  #
119
110
  # @param [String] name the param name
120
111
  # @param [Hash] options information pertinent to the param
121
- # @option [Boolean] options :required
122
- # @option [Boolean] options :legacy
123
- # @option [Boolean] options :recursive
124
- # @option [String,Symbol] options :only Deprecated: use +actions+
125
- # block instead
126
- # @option [String] options :info the doc string for the param
127
- # @option [String] options :type The type of the field.
128
- # e.g. string, integer, boolean, array, hash
129
- # @option [String] options :item_type The type of the items in the field.
112
+ # @option options [Boolean] :required
113
+ # @option options [Boolean] :legacy
114
+ # @option options [Boolean] :recursive
115
+ # @option options [String, Symbol] :only Deprecated: use +actions+ block instead
116
+ # @option options [String] :info the doc string for the param
117
+ # @option options [String] :type The type of the field. e.g. string, integer, boolean, array, hash
118
+ # @option options [String] :item_type The type of the items in the field.
130
119
  # Ideally used when the type of the field is an array or hash.
131
- # @param [Integer] indent how many levels the output should be
132
- # indented from normal
120
+ # @param [Integer] indent how many levels the output should be indented from normal
133
121
  #
134
122
  def parameter_with_indent_level(title, options = {}, indent = 0)
135
123
  options = options.dup
@@ -149,12 +137,22 @@ module Brainstem
149
137
  md_li(text, indent)
150
138
  end
151
139
 
152
-
153
140
  #
154
141
  # Formats the data model for the action.
155
142
  #
156
143
  def format_presents!
157
- if endpoint.presenter
144
+ if endpoint.custom_response.present?
145
+ response_configuration_tree = endpoint.custom_response_configuration_tree
146
+ response_structure_config = response_configuration_tree[:_config]
147
+
148
+ output << md_p(format_custom_response_message(response_structure_config))
149
+ output << md_ul do
150
+ response_configuration_tree.except(:_config).inject("") do |buff, (param_name, param_config)|
151
+ buff << format_param_tree!("", param_name, param_config)
152
+ buff
153
+ end
154
+ end
155
+ elsif endpoint.presenter
158
156
  output << md_h5("Data Model")
159
157
 
160
158
  link = md_a(endpoint.presenter_title, endpoint.relative_presenter_path_from_controller(:markdown))
@@ -163,12 +161,29 @@ module Brainstem
163
161
  end
164
162
  end
165
163
  end
164
+
165
+ def format_custom_response_message(response_config)
166
+ result = "The resulting JSON is "
167
+ result << case response_config[:type]
168
+ when "array"
169
+ if response_config[:item_type] == "hash"
170
+ "an array of objects with the following properties"
171
+ else
172
+ "an array of #{response_config[:item_type].pluralize}"
173
+ end
174
+ when "hash"
175
+ "a hash with the following properties"
176
+ else
177
+ "a #{response_config[:type]}"
178
+ end
179
+
180
+ result
181
+ end
166
182
  end
167
183
  end
168
184
  end
169
185
  end
170
186
  end
171
187
 
172
-
173
- Brainstem::ApiDocs::FORMATTERS[:endpoint][:markdown] = \
188
+ Brainstem::ApiDocs::FORMATTERS[:endpoint][:markdown] =
174
189
  Brainstem::ApiDocs::Formatters::Markdown::EndpointFormatter.method(:call)
@@ -10,67 +10,54 @@ module Brainstem
10
10
  "# #{text}\n\n"
11
11
  end
12
12
 
13
-
14
13
  def md_h2(text)
15
14
  "## #{text}\n\n"
16
15
  end
17
16
 
18
-
19
17
  def md_h3(text)
20
18
  "### #{text}\n\n"
21
19
  end
22
20
 
23
-
24
21
  def md_h4(text)
25
22
  "#### #{text}\n\n"
26
23
  end
27
24
 
28
-
29
25
  def md_h5(text)
30
26
  "##### #{text}\n\n"
31
27
  end
32
28
 
33
-
34
29
  def md_strong(text)
35
30
  "**#{text}**"
36
31
  end
37
32
 
38
-
39
33
  def md_hr
40
34
  "-----\n\n"
41
35
  end
42
36
 
43
-
44
37
  def md_p(text)
45
38
  text + "\n\n"
46
39
  end
47
40
 
48
-
49
41
  def md_code(text, lang = "")
50
42
  "```#{lang}\n#{text}\n```\n\n"
51
43
  end
52
44
 
53
-
54
45
  def md_inline_code(text)
55
46
  "`#{text}`"
56
47
  end
57
48
 
58
-
59
49
  def md_ul(&block)
60
50
  (instance_eval(&block) || "") + "\n\n"
61
51
  end
62
52
 
63
-
64
53
  def md_li(text, indent_level = 0)
65
54
  "#{' ' * (indent_level * 4)}- #{text}\n"
66
55
  end
67
56
 
68
-
69
57
  def md_a(text, link)
70
58
  "[#{text}](#{link})"
71
59
  end
72
60
 
73
-
74
61
  def md_inline_type(type, item_type = nil)
75
62
  return "" if type.blank?
76
63
 
@@ -9,18 +9,15 @@ module Brainstem
9
9
  class PresenterFormatter < AbstractFormatter
10
10
  include Helper
11
11
 
12
-
13
12
  def initialize(presenter, options = {})
14
13
  self.presenter = presenter
15
14
  self.output = ""
16
15
  super options
17
16
  end
18
17
 
19
-
20
18
  attr_accessor :presenter,
21
19
  :output
22
20
 
23
-
24
21
  def call
25
22
  return output if presenter.nodoc?
26
23
 
@@ -35,7 +32,6 @@ module Brainstem
35
32
  output
36
33
  end
37
34
 
38
-
39
35
  #####################################################################
40
36
  private
41
37
  #####################################################################
@@ -44,7 +40,6 @@ module Brainstem
44
40
  output << md_h4(presenter.title)
45
41
  end
46
42
 
47
-
48
43
  def format_brainstem_keys!
49
44
  text = "Top-level key: "
50
45
  text << presenter.brainstem_keys
@@ -54,12 +49,10 @@ module Brainstem
54
49
  output << md_p(text)
55
50
  end
56
51
 
57
-
58
52
  def format_description!
59
53
  output << md_p(presenter.description) unless presenter.description.empty?
60
54
  end
61
55
 
62
-
63
56
  def format_field_leaf(field, indent_level)
64
57
  text = md_inline_code(field.name.to_s)
65
58
  text << md_inline_type(field.type, field.options[:item_type])
@@ -81,7 +74,6 @@ module Brainstem
81
74
  text.chomp!
82
75
  end
83
76
 
84
-
85
77
  def format_field_branch(branch, indent_level = 0)
86
78
  branch.inject("") do |buffer, (name, field)|
87
79
  if nested_field?(field)
@@ -94,12 +86,10 @@ module Brainstem
94
86
  end
95
87
  end
96
88
 
97
-
98
89
  def nested_field?(field)
99
90
  field.respond_to?(:configuration)
100
91
  end
101
92
 
102
-
103
93
  def format_fields!
104
94
  output << md_h5("Fields")
105
95
 
@@ -113,7 +103,6 @@ module Brainstem
113
103
  end
114
104
  end
115
105
 
116
-
117
106
  def format_filters!
118
107
  if presenter.valid_filters.any?
119
108
  output << md_h5("Filters")
@@ -141,7 +130,6 @@ module Brainstem
141
130
  end
142
131
  end
143
132
 
144
-
145
133
  def format_sort_orders!
146
134
  if presenter.valid_sort_orders.any?
147
135
  output << md_h5("Sort Orders")
@@ -169,34 +157,33 @@ module Brainstem
169
157
  end
170
158
  end
171
159
 
172
-
173
160
  def format_associations!
174
- if presenter.valid_associations.any?
175
- output << md_h5("Associations")
176
-
177
- output << "Association Name | Associated Class | Description\n"
178
- output << " -------------- | -------------- | ----------\n"
179
-
180
- output << presenter.valid_associations.inject("") do |buffer, (_, association)|
181
- link = presenter.link_for_association(association)
182
- if link
183
- link = md_a(association.target_class, link)
184
- else
185
- link = association.target_class.to_s
186
- end
161
+ return if presenter.valid_associations.empty?
187
162
 
188
- desc = association.description.to_s
189
- if association.options && association.options[:restrict_to_only]
190
- desc += "." unless desc =~ /\.\s*\z/
191
- desc += " Restricted to queries using the #{md_inline_code("only")} parameter."
192
- desc.strip!
193
- end
163
+ output << md_h5("Associations")
194
164
 
195
- buffer << md_inline_code(association.name) + " | " + link + " | " + desc + "\n"
165
+ output << "Association Name | Associated Class | Description\n"
166
+ output << " -------------- | -------------- | ----------\n"
167
+
168
+ output << presenter.valid_associations.inject("") do |buffer, (_, association)|
169
+ link = presenter.link_for_association(association)
170
+ if link
171
+ link = md_a(association.target_class, link)
172
+ else
173
+ link = association.target_class.to_s
196
174
  end
197
175
 
198
- output << "\n"
176
+ desc = association.description.to_s
177
+ if association.options && association.options[:restrict_to_only]
178
+ desc += "." unless desc =~ /\.\s*\z/
179
+ desc += " Restricted to queries using the #{md_inline_code("only")} parameter."
180
+ desc.strip!
181
+ end
182
+
183
+ buffer << md_inline_code(association.name) + " | " + link + " | " + desc + "\n"
199
184
  end
185
+
186
+ output << "\n"
200
187
  end
201
188
  end
202
189
  end
@@ -204,5 +191,5 @@ module Brainstem
204
191
  end
205
192
  end
206
193
 
207
- Brainstem::ApiDocs::FORMATTERS[:presenter][:markdown] = \
194
+ Brainstem::ApiDocs::FORMATTERS[:presenter][:markdown] =
208
195
  Brainstem::ApiDocs::Formatters::Markdown::PresenterFormatter.method(:call)