brainstem 1.0.0.pre.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,97 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
#
|
4
|
+
# A Command is a callable object that acts as an entrypoint into the
|
5
|
+
# application logic. It is responsible for translating given options into
|
6
|
+
# specific enquiries.
|
7
|
+
#
|
8
|
+
# Internally, it wraps an OptionParser instance returned through its
|
9
|
+
# +option_parser` method. The evaluation of this parser mutates the +options+
|
10
|
+
# hash. This is available to the +call+ method on the instance, which is the
|
11
|
+
# primary point of application logic execution.
|
12
|
+
#
|
13
|
+
module Brainstem
|
14
|
+
module CLI
|
15
|
+
class AbstractCommand
|
16
|
+
|
17
|
+
#
|
18
|
+
# Convenience method for instantiating the command and calling it.
|
19
|
+
#
|
20
|
+
# @return [Brainstem::CLI::AbstractCommand] the instance
|
21
|
+
#
|
22
|
+
def self.call(args = [])
|
23
|
+
instance = new(args)
|
24
|
+
instance.call
|
25
|
+
instance
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
# Returns a new instance of the command with options set.
|
31
|
+
#
|
32
|
+
def initialize(args = [])
|
33
|
+
self.args = args
|
34
|
+
self.options = default_options
|
35
|
+
extract_options!
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
#
|
40
|
+
# Returns the hash of default options used as a base into which cli args
|
41
|
+
# are merged.
|
42
|
+
#
|
43
|
+
def default_options
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
#
|
49
|
+
# Kicks off execution of app-level code. Has available to it +options+,
|
50
|
+
# which contains the options extracted from the command line.
|
51
|
+
#
|
52
|
+
def call
|
53
|
+
raise NotImplementedError,
|
54
|
+
"Override #call and implement your application logic."
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#
|
59
|
+
# Storage for given options.
|
60
|
+
#
|
61
|
+
attr_accessor :options
|
62
|
+
|
63
|
+
|
64
|
+
#
|
65
|
+
# Storage for passed, unparsed args.
|
66
|
+
#
|
67
|
+
attr_accessor :args
|
68
|
+
|
69
|
+
|
70
|
+
#
|
71
|
+
# Extracts command-line options for this specific command based on the
|
72
|
+
# +OptionParser+ specified in +self.option_parser+.
|
73
|
+
#
|
74
|
+
# @return [Hash] the extracted command-line options
|
75
|
+
#
|
76
|
+
def extract_options!
|
77
|
+
option_parser.order!(args)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
#
|
82
|
+
# An +OptionParser+ instance that specifies how options should be
|
83
|
+
# extracted specific to this command.
|
84
|
+
#
|
85
|
+
# Available to this method is the +options+ method, which is the primary
|
86
|
+
# method of communicating options to the +call+ method.
|
87
|
+
#
|
88
|
+
# @return [OptionParser] an instance of OptionParser
|
89
|
+
# @see http://ruby-doc.org/stdlib-2.2.2/libdoc/optparse/rdoc/OptionParser.html
|
90
|
+
#
|
91
|
+
def option_parser
|
92
|
+
raise NotImplementedError,
|
93
|
+
"Must return an instance of OptionParser."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'brainstem/cli/abstract_command'
|
2
|
+
require 'brainstem/api_docs'
|
3
|
+
require 'brainstem/api_docs/exceptions'
|
4
|
+
require 'brainstem/api_docs/builder'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Require all sinks and formatters.
|
8
|
+
#
|
9
|
+
sinks_path = File.expand_path('../../api_docs/sinks/**/*.rb', __FILE__)
|
10
|
+
formatters_path = File.expand_path('../../api_docs/formatters/**/*.rb', __FILE__)
|
11
|
+
Dir.glob(sinks_path).each { |f| require f }
|
12
|
+
Dir.glob(formatters_path).each { |f| require f }
|
13
|
+
|
14
|
+
#
|
15
|
+
# The GenerateApiDocsCommand is responsible for the construction and
|
16
|
+
# intermediation of the two primary components of automatic API doc generation.
|
17
|
+
#
|
18
|
+
# It instantiates both a +Builder+, which is responsible for introspecting and
|
19
|
+
# validation of the host application, and also passes the +Builder+-generated
|
20
|
+
# data structure to the +Sink+, which is responsible for serializing the data
|
21
|
+
# structure to some store (likely transforming the data along the way).
|
22
|
+
#
|
23
|
+
module Brainstem
|
24
|
+
module CLI
|
25
|
+
class GenerateApiDocsCommand < AbstractCommand
|
26
|
+
|
27
|
+
|
28
|
+
def call
|
29
|
+
ensure_sink_specified!
|
30
|
+
construct_builder!
|
31
|
+
present_atlas!
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def default_sink_method
|
36
|
+
Brainstem::ApiDocs::Sinks::ControllerPresenterMultifileSink.method(:new)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def default_options
|
41
|
+
{
|
42
|
+
sink: {
|
43
|
+
method: default_sink_method,
|
44
|
+
options: {}
|
45
|
+
},
|
46
|
+
|
47
|
+
builder: {
|
48
|
+
args_for_atlas: { controller_matches: [] },
|
49
|
+
args_for_introspector: {
|
50
|
+
base_presenter_class: ::Brainstem::ApiDocs.method(:base_presenter_class),
|
51
|
+
base_controller_class: ::Brainstem::ApiDocs.method(:base_controller_class),
|
52
|
+
},
|
53
|
+
},
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
attr_accessor :builder
|
59
|
+
|
60
|
+
|
61
|
+
#########################################################################
|
62
|
+
private
|
63
|
+
#########################################################################
|
64
|
+
|
65
|
+
#
|
66
|
+
# Instantiates a builder, passing the relevant options to it.
|
67
|
+
#
|
68
|
+
def construct_builder!
|
69
|
+
@builder = Brainstem::ApiDocs::Builder.new(builder_options)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
#
|
74
|
+
# Hands the atlas over to the sink.
|
75
|
+
#
|
76
|
+
def present_atlas!
|
77
|
+
sink_method.call(sink_options) << builder.atlas
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
#
|
82
|
+
# Raises an error unless the user specified a destination for the output.
|
83
|
+
#
|
84
|
+
def ensure_sink_specified!
|
85
|
+
raise Brainstem::ApiDocs::NoSinkSpecifiedException unless sink_method
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
#
|
90
|
+
# Utility method for retrieving the sink.
|
91
|
+
#
|
92
|
+
def sink_method
|
93
|
+
@sink_method ||= options[:sink][:method]
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
#
|
98
|
+
# Utility method for retrieving builder options.
|
99
|
+
#
|
100
|
+
def builder_options
|
101
|
+
@builder_options ||= options[:builder]
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
#
|
106
|
+
# Utility method for retrieving sink options.
|
107
|
+
#
|
108
|
+
def sink_options
|
109
|
+
@sink_options ||= options[:sink][:options]
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
#
|
114
|
+
# Defines the option parser for this command.
|
115
|
+
#
|
116
|
+
# @return [OptionParser] the option parser that should mutate the
|
117
|
+
# +options+ hash.
|
118
|
+
#
|
119
|
+
def option_parser
|
120
|
+
OptionParser.new do |opts|
|
121
|
+
opts.banner = "Usage: generate [options]"
|
122
|
+
|
123
|
+
opts.on('-m', '--multifile-presenters-and-controllers',
|
124
|
+
'dumps presenters and controllers to separate files (default)') do |o|
|
125
|
+
options[:sink][:method] = \
|
126
|
+
Brainstem::ApiDocs::Sinks::ControllerPresenterMultifileSink.method(:new)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
opts.on('--host-env-file=PATH', "path to host app's entry file") do |o|
|
131
|
+
options[:builder][:args_for_introspector][:rails_environment_file] = o
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
opts.on('-o RELATIVE_DIR', '--output-dir=RELATIVE_DIR',
|
136
|
+
'specifies directory which to output if relevant') do |o|
|
137
|
+
options[:sink][:options][:write_path] = o
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
opts.on('--base-presenter-class=CLASS', "which class to look up presenters on") do |o|
|
142
|
+
options[:builder][:args_for_introspector][:base_presenter_class] = o
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
opts.on('--base-controller-class=CLASS', "which class to look up controllers on") do |o|
|
147
|
+
options[:builder][:args_for_introspector][:base_controller_class] = o
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
opts.on('--controller-matches=MATCH',
|
152
|
+
'a case-sensitive regexp used to winnow the list of '\
|
153
|
+
'controllers. It is matched against the constant, not '\
|
154
|
+
'underscored name of the controller. Specifying multiple '\
|
155
|
+
'performs a logical AND between Regexen.') do |o|
|
156
|
+
# Trim slashes on passed MATCH.
|
157
|
+
matcher = Regexp.new(o.gsub(/(\A\/)|(\/\z)/, ''), 'i')
|
158
|
+
options[:builder][:args_for_atlas][:controller_matches].push(matcher)
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
opts.on('--markdown', 'use markdown format') do |o|
|
163
|
+
options[:sink][:options][:format] = :markdown
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,300 @@
|
|
1
|
+
require 'brainstem/concerns/inheritable_configuration'
|
2
|
+
require 'active_support/core_ext/object/with_options'
|
3
|
+
|
4
|
+
module Brainstem
|
5
|
+
module Concerns
|
6
|
+
module ControllerDSL
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
include Brainstem::Concerns::InheritableConfiguration
|
9
|
+
|
10
|
+
DEFAULT_BRAINSTEM_PARAMS_CONTEXT = :_default
|
11
|
+
|
12
|
+
included do
|
13
|
+
reset_configuration!
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def reset_configuration!
|
19
|
+
configuration.nest! :_default
|
20
|
+
configuration[:_default].tap do |default|
|
21
|
+
default.nest! :valid_params
|
22
|
+
default.nest! :transforms
|
23
|
+
default.nonheritable! :title
|
24
|
+
default.nonheritable! :description
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
#
|
30
|
+
# In order to correctly scope the DSL, we must have a context under
|
31
|
+
# which keys are stored. The default context is _default (to avoid
|
32
|
+
# any potential collisions with methods named 'default'), and this
|
33
|
+
# context is used as the parent context for all other contexts.
|
34
|
+
#
|
35
|
+
# The context will change, for example, when we are adding keys to the
|
36
|
+
# configuration for actions. In those cases, the context becomes the
|
37
|
+
# +action_name+.
|
38
|
+
#
|
39
|
+
# Any methods that change the context should change it back upon
|
40
|
+
# conclusion so that the assumption of consistent scope inside a block
|
41
|
+
# is possible.
|
42
|
+
#
|
43
|
+
attr_accessor :brainstem_params_context
|
44
|
+
|
45
|
+
|
46
|
+
#
|
47
|
+
# Container method that sets up base scoping for the configuration.
|
48
|
+
#
|
49
|
+
def brainstem_params(&block)
|
50
|
+
self.brainstem_params_context = DEFAULT_BRAINSTEM_PARAMS_CONTEXT
|
51
|
+
class_eval(&block)
|
52
|
+
self.brainstem_params_context = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
#
|
57
|
+
# Specifies that the scope should not be documented. Setting this on
|
58
|
+
# the default context will force the controller to be undocumented,
|
59
|
+
# whereas setting it within an action context will force that action to
|
60
|
+
# be undocumented.
|
61
|
+
#
|
62
|
+
def nodoc!
|
63
|
+
configuration[brainstem_params_context][:nodoc] = true
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
#
|
68
|
+
# Changes context to a specific action context. Allows specification
|
69
|
+
# of per-action configuration.
|
70
|
+
#
|
71
|
+
# Instead of using this method, it's advised simply to use +actions+
|
72
|
+
# with a single method name. While marked as private, since it is
|
73
|
+
# usually used within a +class_eval+ block thanks to
|
74
|
+
# +brainstem_params+, this has little effect.
|
75
|
+
#
|
76
|
+
# Originally, this method was named +action+ for parity with the plural
|
77
|
+
# version. However, this conflicts in multiple ways with Rails, so it
|
78
|
+
# has been renamed.
|
79
|
+
#
|
80
|
+
# @private
|
81
|
+
#
|
82
|
+
# @param [Symbol] name the name of the context
|
83
|
+
# @param [Proc] block the proc to be evaluated in the context
|
84
|
+
#
|
85
|
+
def action_context(name, &block)
|
86
|
+
new_context = name.to_sym
|
87
|
+
old_context = self.brainstem_params_context
|
88
|
+
self.brainstem_params_context = new_context
|
89
|
+
|
90
|
+
self.configuration[new_context] ||= Brainstem::DSL::Configuration.new(
|
91
|
+
self.configuration[DEFAULT_BRAINSTEM_PARAMS_CONTEXT]
|
92
|
+
)
|
93
|
+
|
94
|
+
class_eval(&block)
|
95
|
+
self.brainstem_params_context = old_context
|
96
|
+
end
|
97
|
+
|
98
|
+
private :action_context
|
99
|
+
|
100
|
+
|
101
|
+
#
|
102
|
+
# Invokes +action+ for each symbol in the argument list. Used to
|
103
|
+
# specify shared configuration.
|
104
|
+
#
|
105
|
+
def actions(*axns, &block)
|
106
|
+
axns.flatten.each { |name| action_context name, &block }
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
#
|
111
|
+
# Allows the bulk specification of +:root+ options. Useful for
|
112
|
+
# denoting parameters which are nested under a resource.
|
113
|
+
#
|
114
|
+
# +root+ may be specified as a string or symbol, which will represent
|
115
|
+
# the final root key.
|
116
|
+
#
|
117
|
+
# However, +root+ can also be specified as a Proc / callable object, in
|
118
|
+
# which case it is evaluated at format time, passed the controller
|
119
|
+
# constant. By default, if no argument is passed, it will return the
|
120
|
+
# controller's +brainstem_model_name+ dynamically.
|
121
|
+
#
|
122
|
+
# We provide this functionality as a way to handle parameter inheritance
|
123
|
+
# in subclasses where the brainstem_model_name may not be the same as
|
124
|
+
# the parent class.
|
125
|
+
#
|
126
|
+
# @params root [Symbol,String,Proc] the brainstem model name or a
|
127
|
+
# method accepting the controller constant and returning one
|
128
|
+
#
|
129
|
+
def model_params(root = Proc.new { |klass| klass.brainstem_model_name }, &block)
|
130
|
+
with_options({ root: root.is_a?(Symbol) ? root.to_s : root }, &block)
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
#
|
135
|
+
# Adds a param to the list of valid params, storing
|
136
|
+
# the info sent with it.
|
137
|
+
#
|
138
|
+
# @param [Symbol] field_name the name of the param
|
139
|
+
# @param [Hash] options
|
140
|
+
# @option options [String] :info the documentation for the param
|
141
|
+
# @option options [String,Symbol] :root if this is a nested param,
|
142
|
+
# under which param should it be nested?
|
143
|
+
# @option options [Boolean] :nodoc should this param appear in the
|
144
|
+
# documentation?
|
145
|
+
#
|
146
|
+
def valid(field_name, options = { nodoc: false })
|
147
|
+
valid_params = configuration[brainstem_params_context][:valid_params]
|
148
|
+
valid_params[field_name.to_sym] = options
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
#
|
153
|
+
# Adds a transform to the list of transforms. Used to rename incoming
|
154
|
+
# params to their internal names for usage.
|
155
|
+
#
|
156
|
+
# @example
|
157
|
+
#
|
158
|
+
# brainstem_params do
|
159
|
+
# transform :param_from_frontend => :param_for_backend
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# @param [Hash] transformations An old_param => new_param mapping.
|
163
|
+
#
|
164
|
+
def transform(transformations)
|
165
|
+
transformations.each_pair do |k, v|
|
166
|
+
transforms = configuration[brainstem_params_context][:transforms]
|
167
|
+
transforms[k.to_sym] = v.to_sym
|
168
|
+
end
|
169
|
+
end
|
170
|
+
alias_method :transforms, :transform
|
171
|
+
|
172
|
+
|
173
|
+
#
|
174
|
+
# Specifies which presenter is used for the controller / action.
|
175
|
+
# By default, expects presentation on all methods, and falls back to the
|
176
|
+
# class derived from +brainstem_model_name+ if a name is not
|
177
|
+
# given.
|
178
|
+
#
|
179
|
+
# Setting the +:nodoc+ option marks this presenter as 'internal use only',
|
180
|
+
# and causes formatters to display this as not indicated.
|
181
|
+
#
|
182
|
+
# @param [Class] target_class the target class of the presenter (i.e
|
183
|
+
# the model it presents)
|
184
|
+
# @param [Hash] options options to record with the presenter
|
185
|
+
# @option [Boolean] options :nodoc whether this presenter should not
|
186
|
+
# be output in the documentation.
|
187
|
+
#
|
188
|
+
#
|
189
|
+
def presents(target_class = :default, options = { nodoc: false })
|
190
|
+
raise "`presents` must be a class (in #{self.to_s})" \
|
191
|
+
unless target_class.is_a?(Class) || target_class == :default || target_class.nil?
|
192
|
+
|
193
|
+
target_class = brainstem_model_class if target_class == :default
|
194
|
+
configuration[brainstem_params_context][:presents] = \
|
195
|
+
options.merge(target_class: target_class)
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
#
|
200
|
+
# Specifies a low-level description of a particular context, usually
|
201
|
+
# (but not exclusively) reserved for methods.
|
202
|
+
#
|
203
|
+
# Setting the +:nodoc+ option marks this description as 'internal use
|
204
|
+
# only', and causes formatters not to display a description.
|
205
|
+
#
|
206
|
+
# @param [String] text The description to set
|
207
|
+
# @param [Hash] options options to record with the description
|
208
|
+
# @option [Boolean] options :nodoc whether this description should not
|
209
|
+
# be output in the documentation.
|
210
|
+
#
|
211
|
+
def description(text, options = { nodoc: false })
|
212
|
+
configuration[brainstem_params_context][:description] = \
|
213
|
+
options.merge(info: text)
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
#
|
218
|
+
# Specifies a title to be used in the description of a class. Can also
|
219
|
+
# be used for method section titles.
|
220
|
+
#
|
221
|
+
# Setting the +:nodoc+ option marks this title as 'internal use only',
|
222
|
+
# and causes formatters to fall back to the controller constant or to
|
223
|
+
# the action name as appropriate. If you are trying to set the entire
|
224
|
+
# controller or action as nondocumentable, instead, use the discrete
|
225
|
+
# +.nodoc!+ method in the desired context without a block.
|
226
|
+
#
|
227
|
+
# @param [String] text The title to set
|
228
|
+
# @param [Hash] options options to record with the title
|
229
|
+
# @option [Boolean] options :nodoc whether this title should not be
|
230
|
+
# output in the documentation.
|
231
|
+
#
|
232
|
+
def title(text, options = { nodoc: false })
|
233
|
+
configuration[brainstem_params_context][:title] = \
|
234
|
+
options.merge(info: text)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
#
|
240
|
+
# Lists all valid parameters for the current action. Falls back to the
|
241
|
+
# valid parameters for the default context.
|
242
|
+
#
|
243
|
+
# @params [Symbol] requested_context the context which to look up.
|
244
|
+
#
|
245
|
+
# @return [Hash{String => String, Hash] a hash of pairs of param names and
|
246
|
+
# descriptions or sub-hashes.
|
247
|
+
#
|
248
|
+
def brainstem_valid_params(requested_context = action_name.to_sym, root_param_name = brainstem_model_name)
|
249
|
+
contextual_key(requested_context, :valid_params)
|
250
|
+
.to_h
|
251
|
+
.select do |k, v|
|
252
|
+
root = v[:root].respond_to?(:call) ? v[:root].call(self.class) : v[:root]
|
253
|
+
root.to_s == root_param_name.to_s
|
254
|
+
end
|
255
|
+
end
|
256
|
+
alias_method :brainstem_valid_params_for, :brainstem_valid_params
|
257
|
+
|
258
|
+
|
259
|
+
#
|
260
|
+
# Lists all incoming param keys that will be rewritten to use a different
|
261
|
+
# name for internal usage for the current action.
|
262
|
+
#
|
263
|
+
# Rewrites all params to be symbols for backwards compatibility.
|
264
|
+
#
|
265
|
+
# @params [Symbol] requested_context the context which to look up.
|
266
|
+
#
|
267
|
+
# @return [Hash{Symbol => Symbol}] a map of incoming => internal
|
268
|
+
# param names.
|
269
|
+
#
|
270
|
+
def transforms(requested_context = action_name.to_sym)
|
271
|
+
tforms = contextual_key(requested_context, :transforms).to_h
|
272
|
+
tforms.inject({}) do |memo, (k, v)|
|
273
|
+
memo[k.to_sym] = v.to_sym
|
274
|
+
memo
|
275
|
+
end
|
276
|
+
end
|
277
|
+
alias_method :transforms_for, :transforms
|
278
|
+
|
279
|
+
|
280
|
+
#
|
281
|
+
# Retrieves a specific key in a given context, or if that doesn't exist,
|
282
|
+
# falls back to the parent context.
|
283
|
+
#
|
284
|
+
# @private
|
285
|
+
#
|
286
|
+
# @params [Symbol] context the context in which to first look for the key
|
287
|
+
# @params [Symbol] key the key name to look for
|
288
|
+
#
|
289
|
+
def contextual_key(context, key)
|
290
|
+
if configuration.has_key?(context.to_sym)
|
291
|
+
configuration[context.to_sym][key.to_sym]
|
292
|
+
else
|
293
|
+
configuration[DEFAULT_BRAINSTEM_PARAMS_CONTEXT][key.to_sym]
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
private :contextual_key
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|