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
@@ -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)