Module: Brainstem::Concerns::ControllerDSL::ClassMethods

Defined in:
lib/brainstem/concerns/controller_dsl.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#brainstem_params_contextObject

In order to correctly scope the DSL, we must have a context under which keys are stored. The default context is _default (to avoid any potential collisions with methods named ‘default’), and this context is used as the parent context for all other contexts.

The context will change, for example, when we are adding keys to the configuration for actions. In those cases, the context becomes the action_name.

Any methods that change the context should change it back upon conclusion so that the assumption of consistent scope inside a block is possible.



43
44
45
# File 'lib/brainstem/concerns/controller_dsl.rb', line 43

def brainstem_params_context
  @brainstem_params_context
end

Instance Method Details

#actions(*axns, &block) ⇒ Object

Invokes action for each symbol in the argument list. Used to specify shared configuration.



113
114
115
# File 'lib/brainstem/concerns/controller_dsl.rb', line 113

def actions(*axns, &block)
  axns.flatten.each { |name| action_context name, &block }
end

#brainstem_params(&block) ⇒ Object

Container method that sets up base scoping for the configuration.



49
50
51
52
53
# File 'lib/brainstem/concerns/controller_dsl.rb', line 49

def brainstem_params(&block)
  self.brainstem_params_context = DEFAULT_BRAINSTEM_PARAMS_CONTEXT
  class_eval(&block)
  self.brainstem_params_context = nil
end

#deprecated_type_warningObject

Adds deprecation warning if the type argument is not specified when defining a valid param.



336
337
338
339
340
341
342
343
# File 'lib/brainstem/concerns/controller_dsl.rb', line 336

def deprecated_type_warning
  ActiveSupport::Deprecation.warn(
    'Please specify the `type` of the parameter as the second argument. If not specified, '\
      'it will default to `:string`. This default behavior will be deprecated in the next major '\
      'version and will need to be explicitly specified. e.g. `post.valid :message, :text, required: true`',
    caller
  )
end

#description(text, options = { nodoc: false }) ⇒ Object

Specifies a low-level description of a particular context, usually (but not exclusively) reserved for methods.

Setting the :nodoc option marks this description as ‘internal use only’, and causes formatters not to display a description.

Parameters:

  • text (String)

    The description to set

  • options (Hash) (defaults to: { nodoc: false })

    options to record with the description

  • [Boolean] (Hash)

    a customizable set of options



240
241
242
# File 'lib/brainstem/concerns/controller_dsl.rb', line 240

def description(text, options = { nodoc: false })
  configuration[brainstem_params_context][:description] = options.merge(info: text)
end

#documented!Object

Temporary implementation to track controllers that have been documented.



59
60
61
# File 'lib/brainstem/concerns/controller_dsl.rb', line 59

def documented!
  configuration[brainstem_params_context][:documented] = true
end

#format_field_ancestry_options(field_name_proc, options = {}) ⇒ Object

Formats the ancestry options of the field. Returns a hash with ancestors & root.



290
291
292
293
294
295
# File 'lib/brainstem/concerns/controller_dsl.rb', line 290

def format_field_ancestry_options(field_name_proc, options = {})
  ancestors = options[:ancestors].try(:dup) || []
  ancestors << field_name_proc

  { ancestors: ancestors }.with_indifferent_access.reject { |_, v| v.blank? }
end

#format_field_configuration(type = nil, options = {}, &block) ⇒ Object

Formats the configuration of the field and returns the default configuration if not specified.



301
302
303
304
305
306
307
308
# File 'lib/brainstem/concerns/controller_dsl.rb', line 301

def format_field_configuration(type = nil, options = {}, &block)
  options = type if type.is_a?(Hash) && options.empty?

  options[:type] = sanitize_param_data_type(type, &block)
  options[:item_type] = options[:item_type].to_s if options.has_key?(:item_type)

  DEFAULT_PARAM_OPTIONS.merge(options).with_indifferent_access
end

#format_field_name(field_name_or_proc) ⇒ Proc Also known as: format_root_name

Converts the field name into a Proc.

Parameters:

  • text (String, Symbol, Proc)

    The title to set

Returns:

  • (Proc)


270
271
272
# File 'lib/brainstem/concerns/controller_dsl.rb', line 270

def format_field_name(field_name_or_proc)
  field_name_or_proc.respond_to?(:call) ? field_name_or_proc : Proc.new { field_name_or_proc.to_s }
end

#format_root_ancestry_options(root_name) ⇒ Object

Formats the ancestry options of the field. Returns a hash with ancestors & root.



279
280
281
282
283
284
# File 'lib/brainstem/concerns/controller_dsl.rb', line 279

def format_root_ancestry_options(root_name)
  root_proc = format_root_name(root_name)
  ancestors = [root_proc]

  { root: root_proc, ancestors: ancestors }.with_indifferent_access.reject { |_, v| v.blank? }
end

#model_params(root = Proc.new { |klass| klass.brainstem_model_name }, &block) ⇒ Object

Allows the bulk specification of :root options. Useful for denoting parameters which are nested under a resource.

root may be specified as a string or symbol, which will represent the final root key.

However, root can also be specified as a Proc / callable object, in which case it is evaluated at format time, passed the controller constant. By default, if no argument is passed, it will return the controller’s brainstem_model_name dynamically.

We provide this functionality as a way to handle parameter inheritance in subclasses where the brainstem_model_name may not be the same as the parent class.



137
138
139
# File 'lib/brainstem/concerns/controller_dsl.rb', line 137

def model_params(root = Proc.new { |klass| klass.brainstem_model_name }, &block)
  with_options(format_root_ancestry_options(root), &block)
end

#nodoc!Object

Specifies that the scope should not be documented. Setting this on the default context will force the controller to be undocumented, whereas setting it within an action context will force that action to be undocumented.



70
71
72
# File 'lib/brainstem/concerns/controller_dsl.rb', line 70

def nodoc!
  configuration[brainstem_params_context][:nodoc] = true
end

#presents(target_class = :default, options = { nodoc: false }) ⇒ Object

Specifies which presenter is used for the controller / action. By default, expects presentation on all methods, and falls back to the class derived from brainstem_model_name if a name is not given.

Setting the :nodoc option marks this presenter as ‘internal use only’, and causes formatters to display this as not indicated.

Parameters:

  • target_class (Class) (defaults to: :default)

    the target class of the presenter (i.e the model it presents)

  • options (Hash) (defaults to: { nodoc: false })

    options to record with the presenter

  • [Boolean] (Hash)

    a customizable set of options



218
219
220
221
222
223
224
225
# File 'lib/brainstem/concerns/controller_dsl.rb', line 218

def presents(target_class = :default, options = { nodoc: false })
  raise "`presents` must be a class (in #{self.to_s})" \
    unless target_class.is_a?(Class) || target_class == :default || target_class.nil?

  target_class = brainstem_model_class if target_class == :default
  configuration[brainstem_params_context][:presents] = \
    options.merge(target_class: target_class)
end

#reset_configuration!Object



18
19
20
21
22
23
24
25
26
# File 'lib/brainstem/concerns/controller_dsl.rb', line 18

def reset_configuration!
  configuration.nest! :_default
  configuration[:_default].tap do |default|
    default.nest! :valid_params
    default.nest! :transforms
    default.nonheritable! :title
    default.nonheritable! :description
  end
end

#sanitize_param_data_type(type, &block) ⇒ Object

Returns the type of the param and adds a deprecation warning if not specified.



317
318
319
320
321
322
323
324
# File 'lib/brainstem/concerns/controller_dsl.rb', line 317

def sanitize_param_data_type(type, &block)
  if type.is_a?(Hash) || type.blank?
    deprecated_type_warning
    type = block_given? ? DEFAULT_BLOCK_DATA_TYPE : DEFAULT_DATA_TYPE
  end

  type.to_s
end

#title(text, options = { nodoc: false }) ⇒ Object

Specifies a title to be used in the description of a class. Can also be used for method section titles.

Setting the :nodoc option marks this title as ‘internal use only’, and causes formatters to fall back to the controller constant or to the action name as appropriate. If you are trying to set the entire controller or action as nondocumentable, instead, use the discrete .nodoc! method in the desired context without a block.

Parameters:

  • text (String)

    The title to set

  • options (Hash) (defaults to: { nodoc: false })

    options to record with the title

  • [Boolean] (Hash)

    a customizable set of options



260
261
262
# File 'lib/brainstem/concerns/controller_dsl.rb', line 260

def title(text, options = { nodoc: false })
  configuration[brainstem_params_context][:title] = options.merge(info: text)
end

#transform(transformations) ⇒ Object Also known as: transforms

Adds a transform to the list of transforms. Used to rename incoming params to their internal names for usage.

Examples:


brainstem_params do
  transform :param_from_frontend => :param_for_backend
end

Parameters:

  • transformations (Hash)

    An old_param => new_param mapping.



193
194
195
196
197
198
# File 'lib/brainstem/concerns/controller_dsl.rb', line 193

def transform(transformations)
  transformations.each_pair do |k, v|
    transforms = configuration[brainstem_params_context][:transforms]
    transforms[k.to_sym] = v.to_sym
  end
end

#valid(field_name, type = nil, options = {}, &block) ⇒ Object

Adds a param to the list of valid params, storing the info sent with it.

Parameters:

  • field_name (Symbol)

    the name of the param

  • type (String, Symbol) (defaults to: nil)

    the data type of the field. If not specified, will default to ‘string`.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :info (String)

    the documentation for the param

  • :root (String, Symbol)

    if this is a nested param, under which param should it be nested?

  • :nodoc (Boolean)

    should this param appear in the documentation?

  • :required (Boolean)

    if the param is required for the endpoint

  • :item_type (String, Symbol)

    The data type of the items contained in a field. Ideally used when the data type of the field is an ‘array`, `object` or `hash`.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/brainstem/concerns/controller_dsl.rb', line 159

def valid(field_name, type = nil, options = {}, &block)
  valid_params = configuration[brainstem_params_context][:valid_params]
  field_config = format_field_configuration(type, options, &block)

  # Inherit `nodoc` attribute from parent
  parent_key = (options[:ancestors] || []).reverse.first
  field_config[:nodoc] = true if parent_key && valid_params[parent_key] && valid_params[parent_key][:nodoc]

  # Rollup `required` attribute to ancestors if true
  if field_config[:required]
    (options[:ancestors] || []).reverse.each do |ancestor_key|
      valid_params[ancestor_key][:required] = true if valid_params.has_key?(ancestor_key)
    end
  end

  procified_field_name = format_field_name(field_name)
  valid_params[procified_field_name] = field_config

  with_options(format_field_ancestry_options(procified_field_name, field_config), &block) if block_given?
end