module Brainstem::Concerns::ControllerDSL::ClassMethods

Constants

DEFAULT_FIELD_CONFIG

Attributes

brainstem_params_context[RW]

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.

Public Instance Methods

actions(*axns, &block) click to toggle source

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

# File lib/brainstem/concerns/controller_dsl.rb, line 187
def actions(*axns, &block)
  axns.flatten.each { |name| action_context name, &block }
end
brainstem_params(&block) click to toggle source

Container method that sets up base scoping for the configuration.

# 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
consumes(*mime_types) click to toggle source

Used only for Open API Specification generation. #

A list of MIME types the endpoints can consume. This overrides the default consumes definition on the Info object in the Open API Specification.

@param [Array<String>] mime_types Array of mime types

# File lib/brainstem/concerns/controller_dsl.rb, line 377
def consumes(*mime_types)
  configuration[brainstem_params_context][:consumes] = mime_types.flatten
end
convert_to_proc(field_name_or_proc) click to toggle source

Converts the field name into a Proc.

@param [String, Symbol, Proc] text The title to set @return [Proc]

# File lib/brainstem/concerns/controller_dsl.rb, line 507
def convert_to_proc(field_name_or_proc)
  field_name_or_proc.respond_to?(:call) ? field_name_or_proc : Proc.new { field_name_or_proc.to_s }
end
Also aliased as: format_root_name
deprecated(deprecated) click to toggle source

Used only for Open API Specification generation. #

Declares this operation to be deprecated. Usage of the declared operation should be refrained.

@param [Hash] schemes Array of schemes applicable to the endpoint

# File lib/brainstem/concerns/controller_dsl.rb, line 445
def deprecated(deprecated)
  configuration[brainstem_params_context][:deprecated] = deprecated
end
description(text, options = { nodoc: false, internal: false }) click to toggle source

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.

Setting the :internal option marks this description as 'internal use only', and causes formatters not to display a description unless documentation is generated with `–include-internal` flag.

@param [String] text The description to set @param [Hash] options options to record with the description @option options [Boolean] :nodoc whether this description should not be output in the documentation.

# File lib/brainstem/concerns/controller_dsl.rb, line 147
def description(text, options = { nodoc: false, internal: false })
  configuration[brainstem_params_context][:description] = options.merge(info: text)
end
documented!() click to toggle source

Temporary implementation to track controllers that have been documented.

# File lib/brainstem/concerns/controller_dsl.rb, line 58
def documented!
  configuration[brainstem_params_context][:documented] = true
end
dynamic_key_field(type, options = {}) click to toggle source

Allows defining a field with a dynamic key either under a field block or the custom response block.

@param [Symbol] type the data type of the response. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the response is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 346
def dynamic_key_field(type, options = {})
  field(DYNAMIC_KEY, type, options)
end
dynamic_key_fields(type, options = {}, &block) click to toggle source

Allows defining a field block with a dynamic key for a custom response

@param [Symbol] type the data type of the response. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the response is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 315
def dynamic_key_fields(type, options = {}, &block)
  fields(DYNAMIC_KEY, type, options, &block)
end
external_doc(doc_config) click to toggle source

Used only for Open API Specification generation. #

Additional external documentation for this operation. e.g {

  "description": "Find more info here",
  "url": "https://swagger.io"
}

@param [Hash] doc_config Hash with the `description` & `url` properties of the external documentation.

# File lib/brainstem/concerns/controller_dsl.rb, line 420
def external_doc(doc_config)
  configuration[brainstem_params_context][:external_doc] = doc_config
end
field(name, type, options = {}) click to toggle source

Allows defining a field either under a field block or the custom response block.

@param [Symbol] name the name of the field of the response. @param [Symbol] type the data type of the response. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the response is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 329
def field(name, type, options = {})
  custom_response = configuration[brainstem_params_context][:custom_response]
  raise "`fields` must be nested under a response block" if custom_response.nil?

  formatted_name = convert_to_proc(name)
  custom_response[formatted_name] = format_field_configuration(custom_response, name, type, options)
end
fields(name, type, options = {}, &block) click to toggle source

Allows defining a field block for a custom response

@param [Symbol] name the name of the field block of the response. @param [Symbol] type the data type of the response. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the response is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 295
def fields(name, type, options = {}, &block)
  custom_response = configuration[brainstem_params_context][:custom_response]
  raise "`fields` must be nested under a response block" if custom_response.nil?

  formatted_name = convert_to_proc(name)
  field_block_config = format_field_configuration(custom_response, name, type, options, &block)

  custom_response[formatted_name] = field_block_config
  with_options(format_ancestry_options(formatted_name, field_block_config), &block)
end
format_ancestry_options(field_name_proc, options = {}) click to toggle source

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

# File lib/brainstem/concerns/controller_dsl.rb, line 525
def format_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(configuration_map, name, type, options = {}, &block) click to toggle source

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

# File lib/brainstem/concerns/controller_dsl.rb, line 535
def format_field_configuration(configuration_map, name, type, options = {}, &block)
  field_config = options.with_indifferent_access

  field_config[:type] = type.to_s
  field_config[:dynamic_key] = true if name.present? && name.to_sym == DYNAMIC_KEY

  if options.has_key?(:item_type)
    field_config[:item_type] = field_config[:item_type].to_s
  elsif field_config[:type] == 'array'
    field_config[:item_type] = block_given? ? 'hash' : 'string'
  end

  # Inherit `nodoc` attribute from parent
  parent_key = (field_config[:ancestors] || []).reverse.first
  if parent_key && (parent_field_config = configuration_map[parent_key])
    field_config[:nodoc] ||= !!parent_field_config[:nodoc]
  end

  field_config.delete(:nested_levels) if field_config[:nested_levels].to_i < 2

  DEFAULT_FIELD_CONFIG.merge(field_config).with_indifferent_access
end
format_root_ancestry_options(root_name) click to toggle source

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

# File lib/brainstem/concerns/controller_dsl.rb, line 515
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
format_root_name(field_name_or_proc)
Alias for: convert_to_proc
internal!(description = true) click to toggle source

Specifies that the scope should not be documented unless the `–include-internal` flag is passed in the CLI. 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.

# File lib/brainstem/concerns/controller_dsl.rb, line 78
def internal!(description = true)
  configuration[brainstem_params_context][:internal] = description
end
model_params(root = Proc.new { |klass| klass.brainstem_model_name }, &block) click to toggle source

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.

@params root [Symbol,String,Proc] the brainstem model name or a

method accepting the controller constant and returning one
# File lib/brainstem/concerns/controller_dsl.rb, line 210
def model_params(root = Proc.new { |klass| klass.brainstem_model_name }, &block)
  with_options(format_root_ancestry_options(root), &block)
end
nodoc!(description = true) click to toggle source

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.

# File lib/brainstem/concerns/controller_dsl.rb, line 68
def nodoc!(description = true)
  configuration[brainstem_params_context][:nodoc] = description
end
operation_id(unique_id) click to toggle source

Used only for Open API Specification generation. #

Unique string used to identify the operation. The id MUST be unique among all operations described in the API. Tools and libraries MAY use the operation_id to uniquely identify an operation, therefore, it is recommended to follow common programming naming conventions.

@param [String] unique_id

# File lib/brainstem/concerns/controller_dsl.rb, line 360
def operation_id(unique_id)
  if brainstem_params_context == DEFAULT_BRAINSTEM_PARAMS_CONTEXT
    raise "`operation_id` is endpoint specific and cannot be defined on the controller"
  end

  configuration[brainstem_params_context][:operation_id] = unique_id
end
presents(target_class = :default, options = { nodoc: false, internal: false }) click to toggle source

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.

Setting the :internal option marks this presenter as 'internal use only', and causes formatters to not display this unless documentation is generated with `–include-internal` flag.

@param [Class] target_class the target class of the presenter (i.e the model it presents) @param [Hash] options options to record with the presenter @option options [Boolean] :nodoc whether this presenter should not be output in the documentation.

# File lib/brainstem/concerns/controller_dsl.rb, line 99
def presents(target_class = :default, options = { nodoc: false, internal: 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
produces(*mime_types) click to toggle source

Used only for Open API Specification generation. #

A list of MIME types the endpoints can produce. This overrides the default produces definition on the Info object in the Open API Specification.

@param [Array<String>] mime_types Array of mime types

# File lib/brainstem/concerns/controller_dsl.rb, line 390
def produces(*mime_types)
  configuration[brainstem_params_context][:produces] = mime_types.flatten
end
reset_configuration!() click to toggle source
# 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
    default.nonheritable! :tag
    default.nonheritable! :tag_groups
  end
end
response(type, options = {}, &block) click to toggle source

Allows defining a custom response structure for an action.

@param [Symbol] type the data type of the response. @param [Hash] options @option options [String] :info the documentation for the param @option options [Boolean] :nodoc should this block appear in the documentation? @option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the response is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 271
def response(type, options = {}, &block)
  configuration[brainstem_params_context].nest! :custom_response
  custom_response = configuration[brainstem_params_context][:custom_response]

  custom_response[:_config] = format_field_configuration(
    custom_response,
    nil,
    type,
    options,
    &block
  )
  class_eval(&block) if block_given?
end
schemes(*schemes) click to toggle source

Used only for Open API Specification generation. #

The transfer protocol for the operation. Values MUST be from the list: “http”, “https”, “ws”, “wss”. The value overrides the default schemes definition in the Info Object.

@param [Hash] schemes Array of schemes applicable to the endpoint

# File lib/brainstem/concerns/controller_dsl.rb, line 433
def schemes(*schemes)
  configuration[brainstem_params_context][:schemes] = schemes.flatten
end
security(*schemes) click to toggle source

Used only for Open API Specification generation. #

A declaration of which security schemes are applied for this operation. The list of values describes alternative security schemes that can be used. This definition overrides any declared top-level security. To remove a top-level security declaration, an empty array can be used.

@param [Array<Hash>] schemes Array of security schemes applicable to the endpoint

# File lib/brainstem/concerns/controller_dsl.rb, line 404
def security(*schemes)
  configuration[brainstem_params_context][:security] = schemes.flatten
end
tag(tag_name) click to toggle source

Used only for Open API Specification generation. #

Specifies the tag name to be used in tagging a class.

@param [String] tag_name The name of the tag.

# File lib/brainstem/concerns/controller_dsl.rb, line 159
def tag(tag_name)
  unless brainstem_params_context == DEFAULT_BRAINSTEM_PARAMS_CONTEXT
    raise "`tag` is not endpoint specific and is defined on the controller"
  end

  configuration[brainstem_params_context][:tag] = tag_name
end
tag_groups(*tag_group_names) click to toggle source

Used only for Open API Specification generation. #

Specifies an array of tag names to group the class under. Used for the x-tags OAS vendor extension.

@param [Array<String>] tag_group_names Array of tag group names

# File lib/brainstem/concerns/controller_dsl.rb, line 175
def tag_groups(*tag_group_names)
  unless brainstem_params_context == DEFAULT_BRAINSTEM_PARAMS_CONTEXT
    raise "`tag_groups` is not endpoint specific and is defined on the controller"
  end

  configuration[brainstem_params_context][:tag_groups] = tag_group_names.flatten
end
title(text, options = { nodoc: false, internal: false }) click to toggle source

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 .nodoc! method in the desired context without a block.

Setting the :internal 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 unless documentation is generated with `–include-internal` flag. If you are trying to set the entire controller or action as nondocumentable unless internal, instead, use the .internal! method in the desired context without a block.

@param [String] text The title to set @param [Hash] options options to record with the title @option options [Boolean] :nodoc whether this title should not be output in the documentation.

# File lib/brainstem/concerns/controller_dsl.rb, line 128
def title(text, options = { nodoc: false, internal: false })
  configuration[brainstem_params_context][:title] = options.merge(info: text)
end
transform(transformations) click to toggle source

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

@example

brainstem_params do
  transform :param_from_frontend => :param_for_backend
end

@param [Hash] transformations An old_param => new_param mapping.

# File lib/brainstem/concerns/controller_dsl.rb, line 461
def transform(transformations)
  transformations.each_pair do |k, v|
    transforms = configuration[brainstem_params_context][:transforms]
    transforms[k.to_sym] = v.to_sym
  end
end
Also aliased as: transforms
transforms(transformations)
Alias for: transform
valid(name, type = nil, options = {}, &block) click to toggle source

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

@param [Symbol] name the name of the param @param [String, Symbol] type the data type of the field. If not specified, will default to `string`. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :root if this is a nested param,

under which param should it be nested?

@option options [Boolean] :nodoc should this param appear in the

documentation?

@option options [Boolean] :required if the param is required for

the endpoint

@option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the field is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 231
def valid(name, type = nil, options = {}, &block)
  valid_params = configuration[brainstem_params_context][:valid_params]
  param_config = format_field_configuration(valid_params, name, type, options, &block)

  formatted_name = convert_to_proc(name)
  valid_params[formatted_name] = param_config

  with_options(format_ancestry_options(formatted_name, param_config), &block) if block_given?
end
valid_dynamic_param(type, options = {}, &block) click to toggle source

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

@param [String, Symbol] type the data type of the field. If not specified, will default to `string`. @param [Hash] options @option options [String] :info the documentation for the param @option options [String, Symbol] :root if this is a nested param,

under which param should it be nested?

@option options [Boolean] :nodoc should this param appear in the

documentation?

@option options [Boolean] :required if the param is required for

the endpoint

@option options [String, Symbol] :item_type The data type of the items contained in a field.

Only used when the data type of the field is an `array`.
# File lib/brainstem/concerns/controller_dsl.rb, line 257
def valid_dynamic_param(type, options = {}, &block)
  valid(DYNAMIC_KEY, type, options, &block)
end

Private Instance Methods

action_context(name, &block) click to toggle source

Changes context to a specific action context. Allows specification of per-action configuration.

Instead of using this method, it's advised simply to use actions with a single method name. While marked as private, since it is usually used within a class_eval block thanks to brainstem_params, this has little effect.

Originally, this method was named action for parity with the plural version. However, this conflicts in multiple ways with Rails, so it has been renamed.

@private

@param [Symbol] name the name of the context @param [Proc] block the proc to be evaluated in the context

# File lib/brainstem/concerns/controller_dsl.rb, line 487
def action_context(name, &block)
  new_context = name.to_sym
  old_context = self.brainstem_params_context
  self.brainstem_params_context = new_context

  self.configuration[new_context] ||= Brainstem::DSL::Configuration.new(
    self.configuration[DEFAULT_BRAINSTEM_PARAMS_CONTEXT]
  )

  class_eval(&block)
  self.brainstem_params_context = old_context
end