class Hanami::Controller::Configuration

Configuration for the framework, controllers and actions.

Hanami::Controller has its own global configuration that can be manipulated via `Hanami::Controller.configure`.

Every time that `Hanami::Controller` and `Hanami::Action` are included, that global configuration is being copied to the recipient. The copy will inherit all the settings from the original, but all the subsequent changes aren't reflected from the parent to the children, and viceversa.

This architecture allows to have a global configuration that capture the most common cases for an application, and let controllers and single actions to specify exceptions.

@since 0.2.0

Constants

DEFAULT_ERROR_CODE

Default HTTP code for server side errors

@since 0.2.0 @api private

DEFAULT_FORMATS

Default Mime type to format mapping

@since 0.2.0 @api private

DEFAULT_PUBLIC_DIRECTORY

Default public directory

It serves as base root for file downloads

@since 1.0.0 @api private

Attributes

action_module[W]
cookies[W]
default_charset[W]
default_headers[W]
default_request_format[W]
default_response_format[W]
formats[RW]
handle_exceptions[W]

@attr_writer handle_exceptions [TrueClass,FalseClass] Handle exceptions

with an HTTP status or leave them uncaught

@since 0.2.0

@return void

@see Hanami::Controller::Configuration#handle_exceptions

handled_exceptions[RW]
modules[RW]

Return included modules

@return [Array<Proc>] array of included blocks

@since 0.2.0 @api private

@see Hanami::Controller::Configuration#prepare

public_directory[W]
root_directory[R]

@api private @since 1.0.0

Public Class Methods

for(base) click to toggle source

Return a copy of the configuration of the framework instance associated with the given class.

When multiple instances of Hanami::Controller are used in the same application, we want to make sure that a controller or an action will receive the expected configuration.

@param base [Class, Module] a controller or an action

@return [Hanami::Controller::Configuration] the configuration associated

to the given class.

@since 0.2.0 @api private

@example Direct usage of the framework

require 'hanami/controller'

class Show
  include Hanami::Action
end

Hanami::Controller::Configuration.for(Show)
  # => will duplicate from Hanami::Controller

@example Multiple instances of the framework

require 'hanami/controller'

module MyApp
  Controller = Hanami::Controller.duplicate(self)

  module Controllers::Dashboard
    class Index
      include MyApp::Action

      def call(params)
        # ...
      end
    end
  end
end

class Show
  include Hanami::Action
end

Hanami::Controller::Configuration.for(Show)
  # => will duplicate from Hanami::Controller

Hanami::Controller::Configuration.for(MyApp::Controllers::Dashboard)
  # => will duplicate from MyApp::Controller
# File lib/hanami/controller/configuration.rb, line 98
def self.for(base)
  namespace = Utils::String.namespace(base.name)
  framework = Utils::Class.load("#{namespace}::Controller") || Utils::Class.load!('Hanami::Controller')
  framework.configuration.duplicate
end
new() click to toggle source

Initialize a configuration instance

@return [Hanami::Controller::Configuration] a new configuration's

instance

@since 0.2.0

# File lib/hanami/controller/configuration.rb, line 110
def initialize
  reset!
end

Public Instance Methods

action_module(value = nil) click to toggle source

Specify which is the default action module to be included when we use the `Hanami::Controller.action` method.

This setting is useful when we use multiple instances of the framework in the same process, so we want to ensure that the actions will include `MyApp::Action`, rather than `AnotherApp::Action`.

If not set, the default value is `Hanami::Action`

This is part of a DSL, for this reason when this method is called with an argument, it will set the corresponding instance variable. When called without, it will return the already set value, or the default.

@overload action_module(value)

Sets the given value
@param value [Module] the module to be included in all the actions

@overload action_module

Gets the value
@return [Module]

@since 0.2.0

@see Hanami::Controller::Dsl#action @see Hanami::Controller#duplicate

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.action_module # => Hanami::Action

@example Setting the value

require 'hanami/controller'

module MyAction
end

Hanami::Controller.configure do
  action_module MyAction
end

module Dashboard
  # It includes MyAction, instead of Hanami::Action
  class Index
    include MyAction

    def call(params)
      # ...
    end
  end
end

@example Duplicated framework

require 'hanami/controller'

module MyApp
  Controller = Hanami::Controller.duplicate(self)

  module Controllers::Dashboard
    include MyApp::Controller

    # It includes MyApp::Action, instead of Hanami::Action
    class Index
      include MyApp::Action

      def call(params)
        # ...
      end
    end
  end
end
# File lib/hanami/controller/configuration.rb, line 306
def action_module(value = nil)
  if value.nil?
    @action_module
  else
    @action_module = value
  end
end
cookies(options = nil) click to toggle source

Set default cookies options for all responses

By default this value is an empty hash.

@since 0.4.0

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.cookies # => {}

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  cookies({
    domain: 'hanamirb.org',
    path: '/controller',
    secure: true,
    httponly: true
  })
end
# File lib/hanami/controller/configuration.rb, line 618
def cookies(options = nil)
  if options
    @cookies.merge!(
      options.reject { |_, v| v.nil? }
    )
  else
    @cookies
  end
end
copy!(base) click to toggle source

Copy the configuration for the given action

@param base [Class] the target action

@return void

@since 0.3.0 @api private

@see Hanami::Controller::Configurable.included

# File lib/hanami/controller/configuration.rb, line 728
def copy!(base)
  modules.each do |mod|
    base.class_eval(&mod)
  end
end
default_charset(charset = nil) click to toggle source

Set a charset as default fallback for all the requests without a strict requirement for the charset.

By default this value is nil.

@since 0.3.0

@see Hanami::Action::Mime

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.default_charset # => nil

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  default_charset 'koi8-r'
end
# File lib/hanami/controller/configuration.rb, line 559
def default_charset(charset = nil)
  if charset
    @default_charset = charset
  else
    @default_charset
  end
end
default_headers(headers = nil) click to toggle source

Set default headers for all responses

By default this value is an empty hash.

@since 0.4.0

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.default_headers # => {}

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  default_headers({
    'X-Frame-Options' => 'DENY'
  })
end
# File lib/hanami/controller/configuration.rb, line 586
def default_headers(headers = nil)
  if headers
    @default_headers.merge!(
      headers.reject {|_,v| v.nil? }
    )
  else
    @default_headers
  end
end
default_request_format(format = nil) click to toggle source

Set a format as default fallback for all the requests without a strict requirement for the mime type.

The given format must be coercible to a symbol, and be a valid mime type alias. If it isn't, at the runtime the framework will raise a `Hanami::Controller::UnknownFormatError`.

By default this value is nil.

This is part of a DSL, for this reason when this method is called with an argument, it will set the corresponding instance variable. When called without, it will return the already set value, or the default.

@overload default_request_format(format)

Sets the given value
@param format [#to_sym] the symbol format
@raise [TypeError] if it cannot be coerced to a symbol

@overload default_request_format

Gets the value
@return [Symbol,nil]

@since 0.5.0

@see Hanami::Action::Mime

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.default_request_format # => nil

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  default_request_format :html
end
# File lib/hanami/controller/configuration.rb, line 487
def default_request_format(format = nil)
  if format
    @default_request_format = Utils::Kernel.Symbol(format)
  else
    @default_request_format
  end
end
default_response_format(format = nil) click to toggle source

Set a format to be used for all responses regardless of the request type.

The given format must be coercible to a symbol, and be a valid mime type alias. If it isn't, at the runtime the framework will raise a `Hanami::Controller::UnknownFormatError`.

By default this value is nil.

This is part of a DSL, for this reason when this method is called with an argument, it will set the corresponding instance variable. When called without, it will return the already set value, or the default.

@overload default_response_format(format)

Sets the given value
@param format [#to_sym] the symbol format
@raise [TypeError] if it cannot be coerced to a symbol

@overload default_response_format

Gets the value
@return [Symbol,nil]

@since 0.5.0

@see Hanami::Action::Mime

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.default_response_format # => nil

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  default_response_format :json
end
# File lib/hanami/controller/configuration.rb, line 531
def default_response_format(format = nil)
  if format
    @default_response_format = Utils::Kernel.Symbol(format)
  else
    @default_response_format
  end
end
duplicate() click to toggle source

Duplicate by copying the settings in a new instance.

@return [Hanami::Controller::Configuration] a copy of the configuration

@since 0.2.0 @api private

# File lib/hanami/controller/configuration.rb, line 672
def duplicate
  Configuration.new.tap do |c|
    c.handle_exceptions       = handle_exceptions
    c.handled_exceptions      = handled_exceptions.dup
    c.action_module           = action_module
    c.modules                 = modules.dup
    c.formats                 = formats.dup
    c.default_request_format  = default_request_format
    c.default_response_format = default_response_format
    c.default_charset         = default_charset
    c.default_headers         = default_headers.dup
    c.public_directory        = public_directory
    c.cookies = cookies.dup
  end
end
exception_handler(exception) click to toggle source

Return a callable handler for the given exception

@param exception [Exception] an exception

@since 0.3.0 @api private

@see Hanami::Controller::Configuration#handle_exception

# File lib/hanami/controller/configuration.rb, line 202
def exception_handler(exception)
  exception_handler_for(exception) || DEFAULT_ERROR_CODE
end
exception_handler_for(exception) click to toggle source

Finds configured handler for given exception, or nil if not found.

@param exception [Exception] an exception

@since 1.0.0 @api private

@see Hanami::Controller::Configuration#handle_exception

# File lib/hanami/controller/configuration.rb, line 227
def exception_handler_for(exception)
  @handled_exceptions.each do |exception_class, handler|
    return handler if exception.kind_of?(exception_class)
  end

  nil
end
format(hash) click to toggle source

Register a format

@param hash [Hash] the symbol format must be the key and the mime type

string must be the value of the hash

@since 0.2.0

@see Hanami::Action::Mime

@example

require 'hanami/controller'

Hanami::Controller.configure do
  format custom: 'application/custom'
end

module Articles
  class Index
    include Hanami::Action

    def call(params)
      # ...
    end
  end

  class Show
    include Hanami::Action

    def call(params)
      # ...
      self.format = :custom
    end
  end
end

action = Articles::Index.new

action.call({ 'HTTP_ACCEPT' => 'text/html' })
  # => Content-Type "text/html"
action.format # => :html

action.call({ 'HTTP_ACCEPT' => 'application/custom' })
  # => Content-Type "application/custom"
action.format # => :custom

action = Articles::Show.new

action.call({ 'HTTP_ACCEPT' => 'text/html' })
  # => Content-Type "application/custom"
action.format # => :custom
# File lib/hanami/controller/configuration.rb, line 417
def format(hash)
  symbol, mime_type = *Utils::Kernel.Array(hash)

  @formats[Utils::Kernel.String(mime_type)] = Utils::Kernel.Symbol(symbol)
  @mime_types = nil
end
format_for(mime_type) click to toggle source

Returns a format for the given mime type

@param mime_type [#to_s,#to_str] A mime type

@return [Symbol,nil] the corresponding format, if present

@see Hanami::Controller::Configuration#format

@since 0.2.0 @api private

# File lib/hanami/controller/configuration.rb, line 638
def format_for(mime_type)
  @formats[mime_type]
end
handle_exception(exception) click to toggle source

Specify how to handle an exception with an HTTP status

Raised exceptions will return the configured HTTP status, only if

`handled_exceptions` is set on `true`.

@param exception [Hash] the exception class must be the key and the HTTP

status the value

@since 0.2.0

@see Hanami::Controller::Configuration#handle_exceptions @see Hanami::Controller#configure @see Hanami::Action::Throwable

@example

require 'hanami/controller'

Hanami::Controller.configure do
  handle_exception ArgumentError => 400
end
# File lib/hanami/controller/configuration.rb, line 189
def handle_exception(exception)
  @handled_exceptions.merge!(exception)
  _sort_handled_exceptions!
end
handle_exceptions(value = nil) click to toggle source

Handle exceptions with an HTTP status or let them uncaught

If this value is set to `true`, the configured exceptions will return the specified HTTP status, the rest of them with `500`.

If this value is set to `false`, the exceptions won't be caught.

This is part of a DSL, for this reason when this method is called with an argument, it will set the corresponding instance variable. When called without, it will return the already set value, or the default.

@overload handle_exceptions(value)

Sets the given value
@param value [TrueClass, FalseClass] true or false, default to true

@overload handle_exceptions

Gets the value
@return [TrueClass, FalseClass]

@since 0.2.0

@see Hanami::Controller::Configuration#handle_exception @see Hanami::Controller#configure @see Hanami::Action::Throwable @see httpstatus.es/500

@example Getting the value

require 'hanami/controller'

Hanami::Controller.configuration.handle_exceptions # => true

@example Setting the value

require 'hanami/controller'

Hanami::Controller.configure do
  handle_exceptions false
end
# File lib/hanami/controller/configuration.rb, line 161
def handle_exceptions(value = nil)
  if value.nil?
    @handle_exceptions
  else
    @handle_exceptions = value
  end
end
handled_exception?(exception) click to toggle source

Check if the given exception is handled.

@param exception [Exception] an exception

@since 0.3.2 @api private

@see Hanami::Controller::Configuration#handle_exception

# File lib/hanami/controller/configuration.rb, line 214
def handled_exception?(exception)
  handled_exceptions &&
    !exception_handler_for(exception).nil?
end
load!() click to toggle source

Load the framework

@since 0.3.0 @api private

# File lib/hanami/controller/configuration.rb, line 738
def load!
  freeze
end
mime_type_for(format) click to toggle source

Returns a mime type for the given format

@param format [#to_sym] a format

@return [String,nil] the corresponding mime type, if present

@since 0.2.0 @api private

# File lib/hanami/controller/configuration.rb, line 650
def mime_type_for(format)
  @formats.key(format)
end
mime_types() click to toggle source

Return the configured format's MIME types

@since 0.8.0 @api private

@see Hanami::Controller::Configuration#format @see Hanami::Action::Mime::MIME_TYPES

# File lib/hanami/controller/configuration.rb, line 431
def mime_types
  @mime_types ||= begin
                    ((@formats.keys - DEFAULT_FORMATS.keys) +
                    Hanami::Action::Mime::MIME_TYPES.values).freeze
                  end
end
prepare(&blk) click to toggle source

Configure the logic to be executed when Hanami::Action is included This is useful to DRY code by having a single place where to configure shared behaviors like authentication, sessions, cookies etc.

This method can be called multiple times.

@param blk [Proc] the code block

@return [void]

@raise [ArgumentError] if called without passing a block

@since 0.3.0

@see Hanami::Controller.configure @see Hanami::Controller.duplicate

@example Configure shared logic.

require 'hanami/controller'

Hanami::Controller.configure do
  prepare do
    include Hanami::Action::Session
    include MyAuthentication
    use SomeMiddleWare

    before { authenticate! }
  end
end

module Dashboard
  class Index
    # When Hanami::Action is included, it will:
    #   * Include `Hanami::Action::Session` and `MyAuthentication`
    #   * Configure to use `SomeMiddleWare`
    #   * Configure a `before` callback that triggers `#authenticate!`
    include Hanami::Action

    def call(params)
      # ...
    end
  end
end
# File lib/hanami/controller/configuration.rb, line 357
def prepare(&blk)
  if block_given?
    @modules.push(blk)
  else
    raise ArgumentError.new('Please provide a block')
  end
end
public_directory(value = nil) click to toggle source
# File lib/hanami/controller/configuration.rb, line 658
def public_directory(value = nil)
  if value.nil?
    @public_directory
  else
    @public_directory = root_directory.join(value).to_s
  end
end
reset!() click to toggle source

Reset all the values to the defaults

@since 0.2.0 @api private

# File lib/hanami/controller/configuration.rb, line 702
def reset!
  @handle_exceptions       = true
  @handled_exceptions      = {}
  @modules                 = []
  @formats                 = DEFAULT_FORMATS.dup
  @mime_types              = nil
  @default_request_format  = nil
  @default_response_format = nil
  @default_charset         = nil
  @default_headers         = {}
  @cookies                 = {}
  @root_directory          = ::Pathname.new(Dir.pwd).realpath
  @public_directory        = root_directory.join(DEFAULT_PUBLIC_DIRECTORY).to_s
  @action_module           = ::Hanami::Action
end
restrict_mime_types!(mime_types) click to toggle source

Restrict the MIME types set only to the given set

@param mime_types [Array] the set of MIME types

@since 1.0.0 @api private

@see Hanami::Action::Mime::ClassMethods#accept

# File lib/hanami/controller/configuration.rb, line 446
def restrict_mime_types!(mime_types)
  @mime_types = self.mime_types & mime_types
end

Protected Instance Methods

_sort_handled_exceptions!() click to toggle source

@since 0.5.0 @api private

# File lib/hanami/controller/configuration.rb, line 745
def _sort_handled_exceptions!
  @handled_exceptions = Hash[
    @handled_exceptions.sort{|(ex1,_),(ex2,_)| ex1.ancestors.include?(ex2) ? -1 : 1 }
  ]
end