class Hanami::Extensions::Action::SliceConfiguredAction

Provides slice-specific configuration and behavior for any action class defined within a slice’s module namespace.

@api private @since 2.0.0

Attributes

slice[R]

Public Class Methods

new(slice) click to toggle source
Calls superclass method
# File lib/hanami/extensions/action/slice_configured_action.rb, line 14
def initialize(slice)
  super()
  @slice = slice
end

Public Instance Methods

extended(action_class) click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 19
def extended(action_class)
  configure_action(action_class)
  extend_behavior(action_class)
  define_new
end
inspect() click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 25
def inspect
  "#<#{self.class.name}[#{slice.name}]>"
end

Private Instance Methods

actions_config() click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 155
def actions_config
  slice.config.actions
end
configure_action(action_class) click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 49
def configure_action(action_class)
  action_class.settings.each do |setting|
    # Configure the action from config on the slice, _unless it has already been configured
    # by a parent slice_, and re-configuring it for this slice would make no change.
    #
    # In the case of most slices, its actions config is likely to be the same as its parent
    # (since each slice copies its `config` from its parent), and if we re-apply the config
    # here, then it may possibly overwrite config customisations explicitly made in parent
    # action classes.
    #
    # For example, given an app-level base action class, with custom config:
    #
    #   module MyApp
    #     class Action < Hanami::Action
    #       config.format :json
    #     end
    #   end
    #
    # And then an action in a slice inheriting from it:
    #
    #   module MySlice
    #     module Actions
    #       class SomeAction < MyApp::Action
    #       end
    #     end
    #   end
    #
    # In this case, `SliceConfiguredAction` will be extended two times:
    #
    # 1. When `MyApp::Action` is defined
    # 2. Again when `MySlice::Actions::SomeAction` is defined
    #
    # If we blindly re-configure all action settings each time `SliceConfiguredAction` is
    # extended, then at the point of (2) above, we'd end up overwriting the custom
    # `config.default_response_format` explicitly configured in the `MyApp::Action` base
    # class, leaving `MySlice::Actions::SomeAction` with `config.default_response_format` of
    # `:html` (the default at `Hanami.app.config.actions.default_response_format`), and not
    # the `:json` value configured in its immediate superclass.
    #
    # This would be surprising behavior, and we want to avoid it.
    slice_value = slice.config.actions.public_send(setting.name)
    parent_value = slice.parent.config.actions.public_send(setting.name) if slice.parent

    next if slice.parent && slice_value == parent_value

    action_class.config.public_send(
      :"#{setting.name}=",
      setting.mutable? ? slice_value.dup : slice_value
    )
  end
end
define_new() click to toggle source

@see Hanami::Extensions::Action::InstanceMethods#initialize

Calls superclass method
# File lib/hanami/extensions/action/slice_configured_action.rb, line 32
def define_new
  resolve_view = method(:resolve_paired_view)
  view_context_class = method(:view_context_class)
  resolve_routes = method(:resolve_routes)
  resolve_rack_monitor = method(:resolve_rack_monitor)

  define_method(:new) do |**kwargs|
    super(
      view: kwargs.fetch(:view) { resolve_view.(self) },
      view_context_class: kwargs.fetch(:view_context_class) { view_context_class.() },
      routes: kwargs.fetch(:routes) { resolve_routes.() },
      rack_monitor: kwargs.fetch(:rack_monitor) { resolve_rack_monitor.() },
      **kwargs,
    )
  end
end
extend_behavior(action_class) click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 101
def extend_behavior(action_class)
  if actions_config.sessions.enabled?
    require "hanami/action/session"
    action_class.include Hanami::Action::Session
  end

  if actions_config.csrf_protection
    require "hanami/action/csrf_protection"
    action_class.include Hanami::Action::CSRFProtection
  end

  if actions_config.cookies.enabled?
    require "hanami/action/cookies"
    action_class.include Hanami::Action::Cookies
  end
end
resolve_paired_view(action_class) click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 118
def resolve_paired_view(action_class)
  view_identifiers = actions_config.view_name_inferrer.call(
    action_class_name: action_class.name,
    slice: slice,
  )

  view_identifiers.each do |identifier|
    return slice[identifier] if slice.key?(identifier)
  end

  nil
end
resolve_rack_monitor() click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 151
def resolve_rack_monitor
  slice.app["rack.monitor"] if slice.app.key?("rack.monitor")
end
resolve_routes() click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 147
def resolve_routes
  slice.app["routes"] if slice.app.key?("routes")
end
view_context_class() click to toggle source
# File lib/hanami/extensions/action/slice_configured_action.rb, line 131
def view_context_class
  if Hanami.bundled?("hanami-view")
    return Extensions::View::Context.context_class(slice)
  end

  # If hanami-view isn't bundled, try and find a possible third party context class with the
  # same `Views::Context` name (but don't fall back to automatically defining one).
  if slice.namespace.const_defined?(:Views)
    views_namespace = slice.namespace.const_get(:Views)

    if views_namespace.const_defined?(:Context)
      views_namespace.const_get(:Context)
    end
  end
end