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,116 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'brainstem/concerns/optional'
|
|
3
|
+
require 'brainstem/concerns/formattable'
|
|
4
|
+
|
|
5
|
+
module Brainstem
|
|
6
|
+
module ApiDocs
|
|
7
|
+
class AbstractCollection
|
|
8
|
+
include Enumerable
|
|
9
|
+
extend Forwardable
|
|
10
|
+
include Concerns::Optional
|
|
11
|
+
include Concerns::Formattable
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Creates a new collection with all passed members. Very handy for
|
|
15
|
+
# reduce operations which should return a subset of members but retain
|
|
16
|
+
# the same utility.
|
|
17
|
+
#
|
|
18
|
+
def self.with_members(atlas, *members)
|
|
19
|
+
new(atlas).tap {|n| members.flatten.each { |m| n << m } }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def initialize(atlas, options = {})
|
|
24
|
+
self.atlas = atlas
|
|
25
|
+
self.members = []
|
|
26
|
+
super options
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
attr_accessor :atlas
|
|
31
|
+
|
|
32
|
+
delegate :find_by_class => :atlas
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
#
|
|
36
|
+
# Handy accessor for extracting the last member of the collection.
|
|
37
|
+
#
|
|
38
|
+
def last
|
|
39
|
+
members[-1]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# Appends a pre-existing object to the collection.
|
|
45
|
+
#
|
|
46
|
+
def <<(*objects)
|
|
47
|
+
members.push(*objects.flatten)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# Iterates over each controller in the collection.
|
|
53
|
+
#
|
|
54
|
+
def each(&block)
|
|
55
|
+
members.each(&block)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
#
|
|
60
|
+
# Returns a map of each member formatted as specified.
|
|
61
|
+
#
|
|
62
|
+
def formatted(format, options = {})
|
|
63
|
+
map { |member| member.formatted_as(format, options) }
|
|
64
|
+
.reject(&:empty?)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
#
|
|
69
|
+
# Returns a list of each member's filename.
|
|
70
|
+
#
|
|
71
|
+
# We internally refer to `formatted_with_filename` here because we don't
|
|
72
|
+
# want to include any filenames of empty files (i.e. nodoc).
|
|
73
|
+
#
|
|
74
|
+
def filenames(format)
|
|
75
|
+
formatted_with_filename(format).map { |arr| arr[1] }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
#
|
|
80
|
+
# Returns a map of each formatted member and its suggested filename.
|
|
81
|
+
#
|
|
82
|
+
def formatted_with_filename(format, options = {})
|
|
83
|
+
map { |member| [
|
|
84
|
+
member.formatted_as(format, options),
|
|
85
|
+
member.suggested_filename(format)
|
|
86
|
+
] }
|
|
87
|
+
.reject { |(buffer, _)| buffer.empty? }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def each_formatted_with_filename(format, options = {}, &block)
|
|
92
|
+
formatted_with_filename(format, options)
|
|
93
|
+
.each { |args| block.call(*args) }
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def each_formatted(format, options = {}, &block)
|
|
98
|
+
formatted(format, options)
|
|
99
|
+
.each { |args| block.call(*args) }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def each_filename(format, &block)
|
|
104
|
+
filenames(format).each { |args| block.call(*args) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
#########################################################################
|
|
110
|
+
protected
|
|
111
|
+
#########################################################################
|
|
112
|
+
|
|
113
|
+
attr_accessor :members
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
require 'brainstem/api_docs/resolver'
|
|
3
|
+
require 'brainstem/api_docs/exceptions'
|
|
4
|
+
require 'brainstem/api_docs/endpoint_collection'
|
|
5
|
+
require 'brainstem/api_docs/controller_collection'
|
|
6
|
+
require 'brainstem/api_docs/presenter_collection'
|
|
7
|
+
require 'brainstem/concerns/optional'
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
#
|
|
11
|
+
# The Atlas is an object that makes the information from an introspector
|
|
12
|
+
# available in formatted and raw format.
|
|
13
|
+
#
|
|
14
|
+
module Brainstem
|
|
15
|
+
module ApiDocs
|
|
16
|
+
class Atlas
|
|
17
|
+
extend Forwardable
|
|
18
|
+
include Concerns::Optional
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def initialize(introspector, options = {})
|
|
22
|
+
self.endpoints = EndpointCollection.new(self)
|
|
23
|
+
self.controllers = ControllerCollection.new(self)
|
|
24
|
+
self.presenters = ::Brainstem::ApiDocs::PresenterCollection.new(self)
|
|
25
|
+
self.resolver = Resolver.new(self)
|
|
26
|
+
|
|
27
|
+
self.controller_matches = []
|
|
28
|
+
self.introspector = introspector
|
|
29
|
+
|
|
30
|
+
super options
|
|
31
|
+
|
|
32
|
+
parse_routes!
|
|
33
|
+
extract_presenters!
|
|
34
|
+
validate!
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
attr_accessor :endpoints,
|
|
39
|
+
:controllers,
|
|
40
|
+
:presenters,
|
|
41
|
+
:resolver
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
delegate :find_by_class => :resolver
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
#########################################################################
|
|
48
|
+
private
|
|
49
|
+
#########################################################################
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Lists valid options that may be passed on instantiation.
|
|
54
|
+
#
|
|
55
|
+
def valid_options
|
|
56
|
+
super | [ :controller_matches ]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
#
|
|
61
|
+
# Ensures the atlas is valid before allowing consumers to make requests
|
|
62
|
+
# of it.
|
|
63
|
+
#
|
|
64
|
+
def validate!
|
|
65
|
+
raise InvalidAtlasError, "Atlas is not valid." unless valid?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
#
|
|
70
|
+
# Set and read the introspector.
|
|
71
|
+
#
|
|
72
|
+
attr_accessor :introspector
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Holds +Regexp+s which each controller name must match in order to be
|
|
77
|
+
# included in the list of endpoints.
|
|
78
|
+
#
|
|
79
|
+
attr_accessor :controller_matches
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
# Returns a list of all routes that pass the user's filtering.
|
|
84
|
+
#
|
|
85
|
+
def allowed_routes
|
|
86
|
+
introspector.routes.keep_if(&method(:allow_route?))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
#
|
|
91
|
+
# Constructs +Endpoint+ and +Controller wrappers per route.
|
|
92
|
+
#
|
|
93
|
+
def parse_routes!
|
|
94
|
+
allowed_routes.each do |route|
|
|
95
|
+
if (endpoint = endpoints.find_from_route(route))
|
|
96
|
+
endpoint.merge_http_methods!(route[:http_methods])
|
|
97
|
+
else
|
|
98
|
+
controller = controllers.find_or_create_from_route(route)
|
|
99
|
+
endpoint = endpoints.create_from_route(route, controller)
|
|
100
|
+
|
|
101
|
+
controller.add_endpoint(endpoint)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# Extracts declared presents for each endpoint and converts it into a
|
|
109
|
+
# Presenter wrapper object.
|
|
110
|
+
#
|
|
111
|
+
def extract_presenters!
|
|
112
|
+
valid_presenter_pairs.each do |target_class, const|
|
|
113
|
+
presenter = presenters.find_or_create_from_presenter_collection(target_class, const)
|
|
114
|
+
|
|
115
|
+
endpoints
|
|
116
|
+
.select do |ep|
|
|
117
|
+
declared_presented_class = ep.declared_presented_class
|
|
118
|
+
!declared_presented_class.nil? && declared_presented_class.to_s == target_class
|
|
119
|
+
end
|
|
120
|
+
.each {|ep| ep.presenter = presenter }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# Returns a list of valid +target_class_to_s => PresenterConst+ pairs,
|
|
127
|
+
# determining validity by whether they descend from the base presenter.
|
|
128
|
+
#
|
|
129
|
+
# @return [Hash{String => Class}] valid pairs
|
|
130
|
+
#
|
|
131
|
+
def valid_presenter_pairs
|
|
132
|
+
Brainstem.presenter_collection.presenters.select do |target_class, const|
|
|
133
|
+
introspector.presenters.include? const
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
#
|
|
139
|
+
# Whether this Atlas is valid (i.e. if it has at least one endpoint).
|
|
140
|
+
#
|
|
141
|
+
# @return [Boolean] if the atlas is valid
|
|
142
|
+
#
|
|
143
|
+
def valid?
|
|
144
|
+
endpoints.count > 0
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
#
|
|
149
|
+
# Returns whether a route's controller passes the limiting regexp passed to the
|
|
150
|
+
# generation command.
|
|
151
|
+
#
|
|
152
|
+
def allow_route?(route)
|
|
153
|
+
introspector.controllers.include?(route[:controller]) &&
|
|
154
|
+
controller_matches.all? { |regexp| route[:controller].to_s =~ regexp }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
require 'brainstem/api_docs/introspectors/rails_introspector'
|
|
2
|
+
require 'brainstem/concerns/optional'
|
|
3
|
+
require 'brainstem/api_docs/atlas'
|
|
4
|
+
require 'active_support/core_ext/hash/slice'
|
|
5
|
+
|
|
6
|
+
#
|
|
7
|
+
# This class describes the main API surface for generating API documentation.
|
|
8
|
+
# The command-line utility provided with Brainstem is basically just a thin
|
|
9
|
+
# veneer over top of this class.
|
|
10
|
+
#
|
|
11
|
+
# You can use this to programmatically generate the API docs, or to browse them
|
|
12
|
+
# while inside a REPL.
|
|
13
|
+
#
|
|
14
|
+
module Brainstem
|
|
15
|
+
module ApiDocs
|
|
16
|
+
class Builder
|
|
17
|
+
include Brainstem::Concerns::Optional
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def valid_options
|
|
21
|
+
[
|
|
22
|
+
:introspector_method,
|
|
23
|
+
:atlas_method,
|
|
24
|
+
|
|
25
|
+
:args_for_introspector,
|
|
26
|
+
:args_for_atlas
|
|
27
|
+
]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# @param [Hash] options
|
|
33
|
+
# @option options [Proc] :introspector_method Proc of arity one that
|
|
34
|
+
# returns an Introspector (an object that introspects into
|
|
35
|
+
# the host application, seeking its routes, controllers, and
|
|
36
|
+
# presenters).
|
|
37
|
+
# @option options [Hash] :args_for_introspector Additional arguments to
|
|
38
|
+
# be passed to the introspector on creation.
|
|
39
|
+
# @option options [Hash] :args_for_atlas Additional arguments to be passed
|
|
40
|
+
# to the atlas on creation.
|
|
41
|
+
# @option options [Proc,Object] :introspector_method A method that
|
|
42
|
+
# returns an introspector when called.
|
|
43
|
+
# @option options [Proc,Object] :atlas_method A method that returns an Atlas-like
|
|
44
|
+
# object when called.
|
|
45
|
+
#
|
|
46
|
+
# @see Brainstem::ApiDocs::Introspectors::AbstractIntrospector
|
|
47
|
+
# @see Brainstem::ApiDocs::Introspectors::RailsIntrospector
|
|
48
|
+
#
|
|
49
|
+
def initialize(options = {})
|
|
50
|
+
super
|
|
51
|
+
|
|
52
|
+
build_introspector!
|
|
53
|
+
build_atlas!
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
#
|
|
58
|
+
# Builds an introspector.
|
|
59
|
+
#
|
|
60
|
+
def build_introspector!
|
|
61
|
+
self.introspector = introspector_method.call(args_for_introspector)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Builds an atlas.
|
|
67
|
+
#
|
|
68
|
+
def build_atlas!
|
|
69
|
+
self.atlas = atlas_method.call(introspector, args_for_atlas)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#
|
|
74
|
+
# Arguments to be passed to the introspector on creation.
|
|
75
|
+
#
|
|
76
|
+
# @see Brainstem::ApiDocs::Introspectors::AbstractIntrospector
|
|
77
|
+
# @see Brainstem::ApiDocs::Introspectors::RailsIntrospector
|
|
78
|
+
#
|
|
79
|
+
def args_for_introspector
|
|
80
|
+
@args_for_introspector ||= {}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
# Allows passing args to the introspector if - for example - you are
|
|
86
|
+
# using a custom base controller class.
|
|
87
|
+
#
|
|
88
|
+
attr_writer :args_for_introspector
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
#
|
|
92
|
+
# Arguments to be passed to the atlas on creation.
|
|
93
|
+
#
|
|
94
|
+
# @see Brainstem::ApiDocs::Atlas
|
|
95
|
+
#
|
|
96
|
+
def args_for_atlas
|
|
97
|
+
@args_for_atlas ||= {}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# Allows passing args to the atlas if - for example - you are
|
|
103
|
+
# specifying match terms for the allowable controller set.
|
|
104
|
+
#
|
|
105
|
+
attr_writer :args_for_atlas
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
#
|
|
109
|
+
# A method which returns the introspector which extracts information
|
|
110
|
+
# about the Brainstem-powered API from the host application.
|
|
111
|
+
#
|
|
112
|
+
# Stored as a proc because it's impossible to inject an instantiated
|
|
113
|
+
# object and have it receive args from this class. This is less important
|
|
114
|
+
# in this specific circumstance but is kept for uniformity with
|
|
115
|
+
# +atlas_method+.
|
|
116
|
+
#
|
|
117
|
+
# @return [Proc] a proc of arity 1 which takes an options hash and
|
|
118
|
+
# returns an introspector
|
|
119
|
+
#
|
|
120
|
+
def introspector_method
|
|
121
|
+
@introspector_method ||=
|
|
122
|
+
Introspectors::RailsIntrospector.method(:with_loaded_environment)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
#
|
|
127
|
+
# Allows setting the introspector_method if - for example - you are using
|
|
128
|
+
# Brainstem on a Sinatra app and you need to customize how lookups for
|
|
129
|
+
# presenters, controllers, and routes are performed.
|
|
130
|
+
#
|
|
131
|
+
attr_writer :introspector_method
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
#
|
|
135
|
+
# Holds a reference to the constructed introspector.
|
|
136
|
+
#
|
|
137
|
+
attr_accessor :introspector
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
#
|
|
141
|
+
# A proc of arity 1..2 which takes an introspector and optional options,
|
|
142
|
+
# and which returns a new Atlas.
|
|
143
|
+
#
|
|
144
|
+
# Passed an introspector.
|
|
145
|
+
#
|
|
146
|
+
# @return [Proc] a method to return an atlas
|
|
147
|
+
#
|
|
148
|
+
def atlas_method
|
|
149
|
+
@atlas_method ||= Atlas.method(:new)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
#
|
|
154
|
+
# Allows setting the introspector_method if - for example - you are using
|
|
155
|
+
# an alternative formatter and the requisite information is not present
|
|
156
|
+
# in the +Endpoint+ objects.
|
|
157
|
+
#
|
|
158
|
+
attr_writer :atlas_method
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
#
|
|
162
|
+
# Holds a reference to the constructed atlas.
|
|
163
|
+
#
|
|
164
|
+
attr_accessor :atlas
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'brainstem/concerns/optional'
|
|
2
|
+
require 'brainstem/concerns/formattable'
|
|
3
|
+
require 'active_support/inflector'
|
|
4
|
+
require 'brainstem/api_docs/endpoint_collection'
|
|
5
|
+
require 'forwardable'
|
|
6
|
+
|
|
7
|
+
module Brainstem
|
|
8
|
+
module ApiDocs
|
|
9
|
+
class Controller
|
|
10
|
+
extend Forwardable
|
|
11
|
+
include Concerns::Optional
|
|
12
|
+
include Concerns::Formattable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def initialize(atlas, options = {})
|
|
16
|
+
self.atlas = atlas
|
|
17
|
+
self.endpoints = EndpointCollection.new(atlas)
|
|
18
|
+
super options
|
|
19
|
+
yield self if block_given?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
attr_accessor :const,
|
|
24
|
+
:name,
|
|
25
|
+
:endpoints,
|
|
26
|
+
:filename_pattern,
|
|
27
|
+
:atlas
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
attr_writer :filename_pattern,
|
|
31
|
+
:filename_link_pattern
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def valid_options
|
|
35
|
+
super | [
|
|
36
|
+
:const,
|
|
37
|
+
:name,
|
|
38
|
+
:formatters,
|
|
39
|
+
:filename_pattern,
|
|
40
|
+
:filename_link_pattern
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# Adds an existing endpoint to its endpoint collection.
|
|
47
|
+
#
|
|
48
|
+
def add_endpoint(endpoint)
|
|
49
|
+
self.endpoints << endpoint
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def suggested_filename(format)
|
|
54
|
+
filename_pattern
|
|
55
|
+
.gsub('{{namespace}}', const.to_s.deconstantize.underscore)
|
|
56
|
+
.gsub('{{name}}', name.to_s.split("/").last)
|
|
57
|
+
.gsub('{{extension}}', extension)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def suggested_filename_link(format)
|
|
62
|
+
filename_link_pattern
|
|
63
|
+
.gsub('{{name}}', name.to_s)
|
|
64
|
+
.gsub('{{extension}}', extension)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def extension
|
|
69
|
+
@extension ||= Brainstem::ApiDocs.output_extension
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def filename_pattern
|
|
74
|
+
@filename_pattern ||= Brainstem::ApiDocs.controller_filename_pattern
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def filename_link_pattern
|
|
79
|
+
@filename_link_pattern ||= Brainstem::ApiDocs.controller_filename_link_pattern
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
delegate :configuration => :const
|
|
84
|
+
delegate :find_by_class => :atlas
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def default_configuration
|
|
88
|
+
configuration[:_default]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def nodoc?
|
|
93
|
+
default_configuration[:nodoc]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def title
|
|
98
|
+
contextual_documentation(:title) || const.to_s.demodulize
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def description
|
|
103
|
+
contextual_documentation(:description) || ""
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
#
|
|
108
|
+
# Returns a key if it exists and is documentable.
|
|
109
|
+
#
|
|
110
|
+
def contextual_documentation(key)
|
|
111
|
+
default_configuration.has_key?(key) &&
|
|
112
|
+
!default_configuration[key][:nodoc] &&
|
|
113
|
+
default_configuration[key][:info]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def valid_sorted_endpoints
|
|
118
|
+
endpoints.sorted_with_actions_in_controller(const)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|