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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +383 -32
  5. data/bin/brainstem +6 -0
  6. data/brainstem.gemspec +2 -0
  7. data/docs/api_doc_generator.markdown +175 -0
  8. data/docs/brainstem_executable.markdown +32 -0
  9. data/docs/docgen.png +0 -0
  10. data/docs/docgen_ascii.txt +63 -0
  11. data/docs/executable.png +0 -0
  12. data/docs/executable_ascii.txt +10 -0
  13. data/lib/brainstem/api_docs.rb +146 -0
  14. data/lib/brainstem/api_docs/abstract_collection.rb +116 -0
  15. data/lib/brainstem/api_docs/atlas.rb +158 -0
  16. data/lib/brainstem/api_docs/builder.rb +167 -0
  17. data/lib/brainstem/api_docs/controller.rb +122 -0
  18. data/lib/brainstem/api_docs/controller_collection.rb +40 -0
  19. data/lib/brainstem/api_docs/endpoint.rb +234 -0
  20. data/lib/brainstem/api_docs/endpoint_collection.rb +58 -0
  21. data/lib/brainstem/api_docs/exceptions.rb +8 -0
  22. data/lib/brainstem/api_docs/formatters/abstract_formatter.rb +64 -0
  23. data/lib/brainstem/api_docs/formatters/markdown/controller_formatter.rb +76 -0
  24. data/lib/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter.rb +73 -0
  25. data/lib/brainstem/api_docs/formatters/markdown/endpoint_formatter.rb +169 -0
  26. data/lib/brainstem/api_docs/formatters/markdown/helper.rb +76 -0
  27. data/lib/brainstem/api_docs/formatters/markdown/presenter_formatter.rb +200 -0
  28. data/lib/brainstem/api_docs/introspectors/abstract_introspector.rb +100 -0
  29. data/lib/brainstem/api_docs/introspectors/rails_introspector.rb +232 -0
  30. data/lib/brainstem/api_docs/presenter.rb +225 -0
  31. data/lib/brainstem/api_docs/presenter_collection.rb +97 -0
  32. data/lib/brainstem/api_docs/resolver.rb +73 -0
  33. data/lib/brainstem/api_docs/sinks/abstract_sink.rb +37 -0
  34. data/lib/brainstem/api_docs/sinks/controller_presenter_multifile_sink.rb +93 -0
  35. data/lib/brainstem/api_docs/sinks/stdout_sink.rb +44 -0
  36. data/lib/brainstem/cli.rb +146 -0
  37. data/lib/brainstem/cli/abstract_command.rb +97 -0
  38. data/lib/brainstem/cli/generate_api_docs_command.rb +169 -0
  39. data/lib/brainstem/concerns/controller_dsl.rb +300 -0
  40. data/lib/brainstem/concerns/controller_param_management.rb +30 -9
  41. data/lib/brainstem/concerns/formattable.rb +38 -0
  42. data/lib/brainstem/concerns/inheritable_configuration.rb +3 -2
  43. data/lib/brainstem/concerns/optional.rb +43 -0
  44. data/lib/brainstem/concerns/presenter_dsl.rb +76 -15
  45. data/lib/brainstem/controller_methods.rb +6 -3
  46. data/lib/brainstem/dsl/association.rb +6 -3
  47. data/lib/brainstem/dsl/associations_block.rb +6 -3
  48. data/lib/brainstem/dsl/base_block.rb +2 -4
  49. data/lib/brainstem/dsl/conditional.rb +7 -3
  50. data/lib/brainstem/dsl/conditionals_block.rb +4 -4
  51. data/lib/brainstem/dsl/configuration.rb +184 -8
  52. data/lib/brainstem/dsl/field.rb +6 -3
  53. data/lib/brainstem/dsl/fields_block.rb +2 -3
  54. data/lib/brainstem/help_text.txt +8 -0
  55. data/lib/brainstem/presenter.rb +27 -6
  56. data/lib/brainstem/presenter_validator.rb +5 -2
  57. data/lib/brainstem/time_classes.rb +1 -1
  58. data/lib/brainstem/version.rb +1 -1
  59. data/spec/brainstem/api_docs/abstract_collection_spec.rb +156 -0
  60. data/spec/brainstem/api_docs/atlas_spec.rb +353 -0
  61. data/spec/brainstem/api_docs/builder_spec.rb +100 -0
  62. data/spec/brainstem/api_docs/controller_collection_spec.rb +92 -0
  63. data/spec/brainstem/api_docs/controller_spec.rb +225 -0
  64. data/spec/brainstem/api_docs/endpoint_collection_spec.rb +144 -0
  65. data/spec/brainstem/api_docs/endpoint_spec.rb +346 -0
  66. data/spec/brainstem/api_docs/formatters/abstract_formatter_spec.rb +30 -0
  67. data/spec/brainstem/api_docs/formatters/markdown/controller_formatter_spec.rb +126 -0
  68. data/spec/brainstem/api_docs/formatters/markdown/endpoint_collection_formatter_spec.rb +85 -0
  69. data/spec/brainstem/api_docs/formatters/markdown/endpoint_formatter_spec.rb +261 -0
  70. data/spec/brainstem/api_docs/formatters/markdown/helper_spec.rb +100 -0
  71. data/spec/brainstem/api_docs/formatters/markdown/presenter_formatter_spec.rb +485 -0
  72. data/spec/brainstem/api_docs/introspectors/abstract_introspector_spec.rb +192 -0
  73. data/spec/brainstem/api_docs/introspectors/rails_introspector_spec.rb +170 -0
  74. data/spec/brainstem/api_docs/presenter_collection_spec.rb +84 -0
  75. data/spec/brainstem/api_docs/presenter_spec.rb +519 -0
  76. data/spec/brainstem/api_docs/resolver_spec.rb +72 -0
  77. data/spec/brainstem/api_docs/sinks/abstract_sink_spec.rb +16 -0
  78. data/spec/brainstem/api_docs/sinks/controller_presenter_multifile_sink_spec.rb +56 -0
  79. data/spec/brainstem/api_docs/sinks/stdout_sink_spec.rb +22 -0
  80. data/spec/brainstem/api_docs_spec.rb +58 -0
  81. data/spec/brainstem/cli/abstract_command_spec.rb +91 -0
  82. data/spec/brainstem/cli/generate_api_docs_command_spec.rb +125 -0
  83. data/spec/brainstem/cli_spec.rb +67 -0
  84. data/spec/brainstem/concerns/controller_dsl_spec.rb +471 -0
  85. data/spec/brainstem/concerns/controller_param_management_spec.rb +36 -16
  86. data/spec/brainstem/concerns/formattable_spec.rb +30 -0
  87. data/spec/brainstem/concerns/inheritable_configuration_spec.rb +104 -4
  88. data/spec/brainstem/concerns/optional_spec.rb +48 -0
  89. data/spec/brainstem/concerns/presenter_dsl_spec.rb +202 -31
  90. data/spec/brainstem/dsl/association_spec.rb +18 -2
  91. data/spec/brainstem/dsl/conditional_spec.rb +25 -2
  92. data/spec/brainstem/dsl/configuration_spec.rb +1 -1
  93. data/spec/brainstem/dsl/field_spec.rb +18 -2
  94. data/spec/brainstem/presenter_collection_spec.rb +10 -2
  95. data/spec/brainstem/presenter_spec.rb +32 -0
  96. data/spec/brainstem/presenter_validator_spec.rb +12 -7
  97. data/spec/dummy/rails.rb +49 -0
  98. data/spec/shared/atlas_taker.rb +18 -0
  99. data/spec/shared/formattable.rb +14 -0
  100. data/spec/spec_helper.rb +2 -0
  101. data/spec/spec_helpers/db.rb +1 -1
  102. data/spec/spec_helpers/presenters.rb +20 -14
  103. 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