brainstem 1.0.0.pre.1 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +383 -32
- data/bin/brainstem +6 -0
- data/brainstem.gemspec +2 -0
- data/docs/api_doc_generator.markdown +175 -0
- data/docs/brainstem_executable.markdown +32 -0
- data/docs/docgen.png +0 -0
- data/docs/docgen_ascii.txt +63 -0
- data/docs/executable.png +0 -0
- data/docs/executable_ascii.txt +10 -0
- data/lib/brainstem/api_docs.rb +146 -0
- data/lib/brainstem/api_docs/abstract_collection.rb +116 -0
- data/lib/brainstem/api_docs/atlas.rb +158 -0
- data/lib/brainstem/api_docs/builder.rb +167 -0
- data/lib/brainstem/api_docs/controller.rb +122 -0
- data/lib/brainstem/api_docs/controller_collection.rb +40 -0
- data/lib/brainstem/api_docs/endpoint.rb +234 -0
- data/lib/brainstem/api_docs/endpoint_collection.rb +58 -0
- data/lib/brainstem/api_docs/exceptions.rb +8 -0
- data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +64 -0
- data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +73 -0
- data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +169 -0
- data/lib/brainstem/api_docs/formatters/markdown/helper.rb +76 -0
- data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +200 -0
- data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +100 -0
- data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +232 -0
- data/lib/brainstem/api_docs/presenter.rb +225 -0
- data/lib/brainstem/api_docs/presenter_collection.rb +97 -0
- data/lib/brainstem/api_docs/resolver.rb +73 -0
- data/lib/brainstem/api_docs/sinks/abstract_sink.rb +37 -0
- data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +93 -0
- data/lib/brainstem/api_docs/sinks/stdout_sink.rb +44 -0
- data/lib/brainstem/cli.rb +146 -0
- data/lib/brainstem/cli/abstract_command.rb +97 -0
- data/lib/brainstem/cli/generate_api_docs_command.rb +169 -0
- data/lib/brainstem/concerns/controller_dsl.rb +300 -0
- data/lib/brainstem/concerns/controller_param_management.rb +30 -9
- data/lib/brainstem/concerns/formattable.rb +38 -0
- data/lib/brainstem/concerns/inheritable_configuration.rb +3 -2
- data/lib/brainstem/concerns/optional.rb +43 -0
- data/lib/brainstem/concerns/presenter_dsl.rb +76 -15
- data/lib/brainstem/controller_methods.rb +6 -3
- data/lib/brainstem/dsl/association.rb +6 -3
- data/lib/brainstem/dsl/associations_block.rb +6 -3
- data/lib/brainstem/dsl/base_block.rb +2 -4
- data/lib/brainstem/dsl/conditional.rb +7 -3
- data/lib/brainstem/dsl/conditionals_block.rb +4 -4
- data/lib/brainstem/dsl/configuration.rb +184 -8
- data/lib/brainstem/dsl/field.rb +6 -3
- data/lib/brainstem/dsl/fields_block.rb +2 -3
- data/lib/brainstem/help_text.txt +8 -0
- data/lib/brainstem/presenter.rb +27 -6
- data/lib/brainstem/presenter_validator.rb +5 -2
- data/lib/brainstem/time_classes.rb +1 -1
- data/lib/brainstem/version.rb +1 -1
- data/spec/brainstem/api_docs/abstract_collection_spec.rb +156 -0
- data/spec/brainstem/api_docs/atlas_spec.rb +353 -0
- data/spec/brainstem/api_docs/builder_spec.rb +100 -0
- data/spec/brainstem/api_docs/controller_collection_spec.rb +92 -0
- data/spec/brainstem/api_docs/controller_spec.rb +225 -0
- data/spec/brainstem/api_docs/endpoint_collection_spec.rb +144 -0
- data/spec/brainstem/api_docs/endpoint_spec.rb +346 -0
- data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +30 -0
- data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +126 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +85 -0
- data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +261 -0
- data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +100 -0
- data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +485 -0
- data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +192 -0
- data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +170 -0
- data/spec/brainstem/api_docs/presenter_collection_spec.rb +84 -0
- data/spec/brainstem/api_docs/presenter_spec.rb +519 -0
- data/spec/brainstem/api_docs/resolver_spec.rb +72 -0
- data/spec/brainstem/api_docs/sinks/abstract_sink_spec.rb +16 -0
- data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +56 -0
- data/spec/brainstem/api_docs/sinks/stdout_sink_spec.rb +22 -0
- data/spec/brainstem/api_docs_spec.rb +58 -0
- data/spec/brainstem/cli/abstract_command_spec.rb +91 -0
- data/spec/brainstem/cli/generate_api_docs_command_spec.rb +125 -0
- data/spec/brainstem/cli_spec.rb +67 -0
- data/spec/brainstem/concerns/controller_dsl_spec.rb +471 -0
- data/spec/brainstem/concerns/controller_param_management_spec.rb +36 -16
- data/spec/brainstem/concerns/formattable_spec.rb +30 -0
- data/spec/brainstem/concerns/inheritable_configuration_spec.rb +104 -4
- data/spec/brainstem/concerns/optional_spec.rb +48 -0
- data/spec/brainstem/concerns/presenter_dsl_spec.rb +202 -31
- data/spec/brainstem/dsl/association_spec.rb +18 -2
- data/spec/brainstem/dsl/conditional_spec.rb +25 -2
- data/spec/brainstem/dsl/configuration_spec.rb +1 -1
- data/spec/brainstem/dsl/field_spec.rb +18 -2
- data/spec/brainstem/presenter_collection_spec.rb +10 -2
- data/spec/brainstem/presenter_spec.rb +32 -0
- data/spec/brainstem/presenter_validator_spec.rb +12 -7
- data/spec/dummy/rails.rb +49 -0
- data/spec/shared/atlas_taker.rb +18 -0
- data/spec/shared/formattable.rb +14 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helpers/db.rb +1 -1
- data/spec/spec_helpers/presenters.rb +20 -14
- metadata +106 -6
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'brainstem/api_docs/abstract_collection'
|
|
2
|
+
require 'brainstem/api_docs/controller'
|
|
3
|
+
|
|
4
|
+
module Brainstem
|
|
5
|
+
module ApiDocs
|
|
6
|
+
class ControllerCollection < AbstractCollection
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Creates a new controller from a route object and appends it to the
|
|
11
|
+
# collection.
|
|
12
|
+
def create_from_route(route)
|
|
13
|
+
Controller.new(atlas,
|
|
14
|
+
const: route[:controller],
|
|
15
|
+
name: route[:controller_name].split("/").last
|
|
16
|
+
).tap { |controller| self.<< controller }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
#
|
|
21
|
+
# Finds a controller from a route object.
|
|
22
|
+
#
|
|
23
|
+
def find_by_route(route)
|
|
24
|
+
find do |controller|
|
|
25
|
+
controller.const == route[:controller]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Finds a controller from a route object or creates one if it does not
|
|
32
|
+
# exist.
|
|
33
|
+
#
|
|
34
|
+
def find_or_create_from_route(route)
|
|
35
|
+
find_by_route(route) || create_from_route(route)
|
|
36
|
+
end
|
|
37
|
+
alias_method :find_or_create_by_route, :find_or_create_from_route
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
require 'brainstem/concerns/optional'
|
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
|
3
|
+
require 'brainstem/concerns/formattable'
|
|
4
|
+
require 'forwardable'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
|
|
7
|
+
#
|
|
8
|
+
# Per-endpoint holder for presenter and controller information.
|
|
9
|
+
#
|
|
10
|
+
module Brainstem
|
|
11
|
+
module ApiDocs
|
|
12
|
+
class Endpoint
|
|
13
|
+
extend Forwardable
|
|
14
|
+
include Concerns::Optional
|
|
15
|
+
include Concerns::Formattable
|
|
16
|
+
|
|
17
|
+
ACTION_ORDER = %w(index show create update delete)
|
|
18
|
+
|
|
19
|
+
def valid_options
|
|
20
|
+
super | [
|
|
21
|
+
:path,
|
|
22
|
+
:http_methods,
|
|
23
|
+
:controller,
|
|
24
|
+
:controller_name,
|
|
25
|
+
:action,
|
|
26
|
+
:presenter
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def initialize(atlas, options = {})
|
|
32
|
+
self.atlas = atlas
|
|
33
|
+
super options
|
|
34
|
+
yield self if block_given?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
attr_accessor :path,
|
|
39
|
+
:http_methods,
|
|
40
|
+
:controller,
|
|
41
|
+
:controller_name,
|
|
42
|
+
:action,
|
|
43
|
+
:atlas
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Pretty prints each endpoint.
|
|
48
|
+
#
|
|
49
|
+
def to_s
|
|
50
|
+
"#{http_methods.join(" / ")} #{path}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
#
|
|
55
|
+
# Merges http methods (for de-duping Rails' routes).
|
|
56
|
+
#
|
|
57
|
+
def merge_http_methods!(methods)
|
|
58
|
+
self.http_methods |= methods
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# Sorts this endpoint in comparison to other endpoints.
|
|
64
|
+
#
|
|
65
|
+
# Follows a manually defined order of precedence (+ACTION_ORDER+). The
|
|
66
|
+
# earlier an action name appears on the list, the earlier it is sorted.
|
|
67
|
+
#
|
|
68
|
+
# In the event that an action is not on the list, it is sorted after any
|
|
69
|
+
# listed routes, and then sorted alphabetically among the remainder.
|
|
70
|
+
#
|
|
71
|
+
def <=>(other)
|
|
72
|
+
|
|
73
|
+
# Any unordered routes are assigned an index of +ACTION_ORDER.count+.
|
|
74
|
+
ordered_actions_count = ACTION_ORDER.count
|
|
75
|
+
own_action_priority = ACTION_ORDER.index(action.to_s) || ordered_actions_count
|
|
76
|
+
other_action_priority = ACTION_ORDER.index(other.action.to_s) || ordered_actions_count
|
|
77
|
+
|
|
78
|
+
# If the priorities are unequal (i.e. one or both are named; duplicates
|
|
79
|
+
# should not exist for named routes):
|
|
80
|
+
if own_action_priority != other_action_priority
|
|
81
|
+
|
|
82
|
+
# Flip order if this action's priority is greater than the other.
|
|
83
|
+
# other_action_priority <=> own_action_priority
|
|
84
|
+
own_action_priority <=> other_action_priority
|
|
85
|
+
|
|
86
|
+
# If the priorities are equal, i.e. both not in the list:
|
|
87
|
+
else
|
|
88
|
+
|
|
89
|
+
# Flip order if this action's name is alphabetically later.
|
|
90
|
+
action.to_s <=> other.action.to_s
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
################################################################################
|
|
96
|
+
# Derived fields
|
|
97
|
+
################################################################################
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Is the entire endpoint undocumentable?
|
|
101
|
+
#
|
|
102
|
+
def nodoc?
|
|
103
|
+
action_configuration[:nodoc]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def title
|
|
108
|
+
@title ||= contextual_documentation(:title) || action.to_s.humanize
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def description
|
|
113
|
+
@description ||= contextual_documentation(:description) || ""
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def valid_params
|
|
118
|
+
@valid_params ||= key_with_default_fallback(:valid_params)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
#
|
|
123
|
+
# Returns a hash of all root-level params with values of an array of
|
|
124
|
+
# the parameters nested underneath, or +nil+ in the event they are
|
|
125
|
+
# root-level non-nested params.
|
|
126
|
+
#
|
|
127
|
+
# @return [Hash{Symbol => Array,NilClass}] root keys and the keys
|
|
128
|
+
# nested under them, or nil if not a nested param.
|
|
129
|
+
#
|
|
130
|
+
def root_param_keys
|
|
131
|
+
@root_param_keys ||= begin
|
|
132
|
+
valid_params.to_h
|
|
133
|
+
.inject({}) do |hsh, (field_name, data)|
|
|
134
|
+
next hsh if data[:nodoc]
|
|
135
|
+
|
|
136
|
+
if data.has_key?(:root)
|
|
137
|
+
key = data[:root].respond_to?(:call) ? data[:root].call(controller.const) : data[:root]
|
|
138
|
+
(hsh[key] ||= []) << field_name
|
|
139
|
+
else
|
|
140
|
+
hsh[field_name] = nil
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
hsh
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
#
|
|
150
|
+
# Retrieves the +presents+ settings.
|
|
151
|
+
#
|
|
152
|
+
def valid_presents
|
|
153
|
+
key_with_default_fallback(:presents) || {}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
#
|
|
158
|
+
# Used to retrieve this endpoint's presenter constant.
|
|
159
|
+
#
|
|
160
|
+
def declared_presented_class
|
|
161
|
+
valid_presents.has_key?(:target_class) &&
|
|
162
|
+
!valid_presents[:nodoc] &&
|
|
163
|
+
valid_presents[:target_class]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
#
|
|
168
|
+
# Stores the +ApiDocs::Presenter+ object associated with this endpoint.
|
|
169
|
+
#
|
|
170
|
+
attr_accessor :presenter
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
################################################################################
|
|
174
|
+
# Configuration Helpers
|
|
175
|
+
#################################################################################
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# Helper for retrieving configuration from its controller.
|
|
179
|
+
#
|
|
180
|
+
delegate :configuration => :controller
|
|
181
|
+
delegate :find_by_class => :atlas
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
#
|
|
185
|
+
# Helper for retrieving action-specific configuration from the controller.
|
|
186
|
+
#
|
|
187
|
+
def action_configuration
|
|
188
|
+
configuration[action] || {}
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
#
|
|
193
|
+
# Retrieves default action context from the controller.
|
|
194
|
+
#
|
|
195
|
+
def default_configuration
|
|
196
|
+
configuration[:_default] || {}
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
#
|
|
201
|
+
# Returns a key if it exists and is documentable
|
|
202
|
+
#
|
|
203
|
+
def contextual_documentation(key)
|
|
204
|
+
action_configuration.has_key?(key) &&
|
|
205
|
+
!action_configuration[key][:nodoc] &&
|
|
206
|
+
action_configuration[key][:info]
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def key_with_default_fallback(key)
|
|
211
|
+
action_configuration[key] || default_configuration[key]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def presenter_title
|
|
216
|
+
presenter && presenter.title
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
#
|
|
221
|
+
# Returns the relative path from this endpoint's controller to this
|
|
222
|
+
# endpoint's declared presenter.
|
|
223
|
+
#
|
|
224
|
+
def relative_presenter_path_from_controller(format)
|
|
225
|
+
if presenter && controller
|
|
226
|
+
controller_path = Pathname.new(File.dirname(controller.suggested_filename_link(format)))
|
|
227
|
+
presenter_path = Pathname.new(presenter.suggested_filename_link(format))
|
|
228
|
+
|
|
229
|
+
presenter_path.relative_path_from(controller_path).to_s
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'brainstem/api_docs/abstract_collection'
|
|
2
|
+
require 'brainstem/api_docs/endpoint'
|
|
3
|
+
require 'brainstem/concerns/formattable'
|
|
4
|
+
|
|
5
|
+
module Brainstem
|
|
6
|
+
module ApiDocs
|
|
7
|
+
class EndpointCollection < AbstractCollection
|
|
8
|
+
include Concerns::Formattable
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_from_route(route)
|
|
12
|
+
find do |endpoint|
|
|
13
|
+
endpoint.path == route[:path] &&
|
|
14
|
+
endpoint.controller.const == route[:controller] &&
|
|
15
|
+
endpoint.action == route[:action]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias_method :find_by_route, :find_from_route
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def create_from_route(route, controller)
|
|
23
|
+
Endpoint.new(atlas) do |ep|
|
|
24
|
+
ep.path = route[:path]
|
|
25
|
+
ep.http_methods = route[:http_methods]
|
|
26
|
+
ep.controller = controller
|
|
27
|
+
ep.controller_name = route[:controller_name]
|
|
28
|
+
ep.action = route[:action]
|
|
29
|
+
end.tap { |endpoint| self.<< endpoint }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def only_documentable
|
|
34
|
+
self.class.with_members(atlas, reject(&:nodoc?))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def with_declared_presented_class
|
|
39
|
+
self.class.with_members(atlas, reject { |m| m.declared_presented_class.nil? })
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def sorted
|
|
44
|
+
self.class.with_members(atlas, sort)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def with_actions_in_controller(const)
|
|
49
|
+
self.class.with_members(atlas, reject { |m| !const.method_defined?(m.action) })
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def sorted_with_actions_in_controller(const)
|
|
54
|
+
with_actions_in_controller(const).sorted
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module Brainstem
|
|
2
|
+
module ApiDocs
|
|
3
|
+
class IncorrectIntrospectorForAppException < StandardError; end
|
|
4
|
+
class InvalidIntrospectorError < StandardError; end
|
|
5
|
+
class InvalidAtlasError < StandardError; end
|
|
6
|
+
class NoSinkSpecifiedException < StandardError; end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'brainstem/api_docs'
|
|
2
|
+
require 'brainstem/api_docs/exceptions'
|
|
3
|
+
require 'brainstem/concerns/optional'
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# A formatter is fundamentally just a function that, when +#call+ed, accepts an
|
|
7
|
+
# atlas and returns the whole or portion of its data in a readable format.
|
|
8
|
+
#
|
|
9
|
+
# There are (informally) several types of formatters, and you should select
|
|
10
|
+
# among them appropriately when developing your own:
|
|
11
|
+
#
|
|
12
|
+
# 1. Entity
|
|
13
|
+
#
|
|
14
|
+
# Turns a single data entity into its formatted version. For example, if
|
|
15
|
+
# formatting a Post object, call this formatter a
|
|
16
|
+
# +<Format>PostFormatter+.
|
|
17
|
+
#
|
|
18
|
+
# 2. Collection
|
|
19
|
+
#
|
|
20
|
+
# Turns a collection of formatted data entities into a single unit.
|
|
21
|
+
# Usually this will involve concatenating and/or rejecting inappropriate
|
|
22
|
+
# output. For example, if you have a collection of Markdown strings from
|
|
23
|
+
# the MarkdownPostFormatter, you might want to generate the whole section
|
|
24
|
+
# of documentation by using a +MarkdownPostCollectionFormatter+.
|
|
25
|
+
#
|
|
26
|
+
# 3. Aggregate
|
|
27
|
+
#
|
|
28
|
+
# A combination of entity and collection formatters. Knows how to turn a
|
|
29
|
+
# collection of unformatted entities into a single formatted document.
|
|
30
|
+
# Not as composable as the two used seperately, but far simpler. This
|
|
31
|
+
# should be named +MarkdownAggregatePostFormatter+.
|
|
32
|
+
#
|
|
33
|
+
# At the time of writing, there is no actual requirement to use these naming
|
|
34
|
+
# conventions, but it is highly recommended for clarity of purpose.
|
|
35
|
+
#
|
|
36
|
+
module Brainstem
|
|
37
|
+
module ApiDocs
|
|
38
|
+
module Formatters
|
|
39
|
+
class AbstractFormatter
|
|
40
|
+
include Concerns::Optional
|
|
41
|
+
|
|
42
|
+
#
|
|
43
|
+
# Convenience class method for instantiating and calling.
|
|
44
|
+
#
|
|
45
|
+
def self.call(*args)
|
|
46
|
+
new(*args).call
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def initialize(*args)
|
|
51
|
+
super args.last || {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Override to transform atlas data into serialized format.
|
|
57
|
+
#
|
|
58
|
+
def call
|
|
59
|
+
raise NotImplementedError
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require 'brainstem/api_docs/formatters/abstract_formatter'
|
|
2
|
+
require 'brainstem/api_docs/formatters/markdown/helper'
|
|
3
|
+
|
|
4
|
+
module Brainstem
|
|
5
|
+
module ApiDocs
|
|
6
|
+
module Formatters
|
|
7
|
+
module Markdown
|
|
8
|
+
class ControllerFormatter < AbstractFormatter
|
|
9
|
+
include Helper
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# Declares the options that are permissable to set on this instance.
|
|
13
|
+
#
|
|
14
|
+
def valid_options
|
|
15
|
+
super | [
|
|
16
|
+
:include_actions
|
|
17
|
+
]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
attr_accessor :controller,
|
|
22
|
+
:include_actions,
|
|
23
|
+
:output
|
|
24
|
+
|
|
25
|
+
alias_method :include_actions?, :include_actions
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def initialize(controller, options = {})
|
|
29
|
+
self.controller = controller
|
|
30
|
+
self.output = ""
|
|
31
|
+
self.include_actions = false
|
|
32
|
+
super options
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def call
|
|
37
|
+
return output if controller.nodoc?
|
|
38
|
+
format_title!
|
|
39
|
+
format_description!
|
|
40
|
+
format_actions!
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
#####################################################################
|
|
45
|
+
private
|
|
46
|
+
#####################################################################
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def format_title!
|
|
50
|
+
output << md_h2(controller.title)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_description!
|
|
55
|
+
output << md_p(controller.description) unless controller.description.empty?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def format_actions!
|
|
60
|
+
return unless include_actions?
|
|
61
|
+
|
|
62
|
+
output << md_h3("Endpoints")
|
|
63
|
+
|
|
64
|
+
output << controller.valid_sorted_endpoints
|
|
65
|
+
.formatted_as(:markdown, zero_text: "No endpoints were found.")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
Brainstem::ApiDocs::FORMATTERS[:controller][:markdown] = \
|
|
76
|
+
Brainstem::ApiDocs::Formatters::Markdown::ControllerFormatter.method(:call)
|