phallguy/scorpion

View on GitHub
lib/scorpion/rails/controller.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
require "scorpion/nest"

module Scorpion
  module Rails

    # Adds a scorpion nest to support injection into rails controllers.
    module Controller

      ENV_KEY = "scorpion.instance".freeze

      # Fetch an object from the controller's {#scorpion}.
      # @see Scorpion#fetch
      def fetch( *args, &block )
        scorpion.fetch *args, &block
      end
      private :fetch


      # @overload scorpion
      #   @return [Scorpion] the current scorpion
      # @overload scorpion( scope )
      #   Stings the given `scope` with the current scorpion.
      #   @param [ActiveRecord::Relation,#with_scorpion] an ActiveRecord relation,
      #     scope or model class.
      #   @return [ActiveRecord::Relation] scorpion scoped relation.

      def self.included( base )
        # Setup dependency injection
        base.send :include, Scorpion::Object
        base.send :include, Scorpion::Rails::Nest

        base.around_action :with_scorpion

        base.class_eval do
          if respond_to?( :helper_method )
            helper_method :scorpion
          end

          # Defined here to override the #scorpion method provided by Scorpion::Object.
          def scorpion( scope = nil )
            if scope
              super
            else
              ensure_scorpion( request.env[ENV_KEY] )
            end
          end
        end

        super
      end

      private

        # Fetch a scorpion and feed the controller it's dependencies
        def prepare_scorpion( scorpion )
          scorpion.prepare do |hunter|
            # Allow dependencies to access the controller
            hunter.hunt_for AbstractController::Base, return: self

            # Allow dependencies to access the current request/response
            hunter.hunt_for ActionDispatch::Request do |hunt|
              hunt.fetch( AbstractController::Base ).request
            end
            hunter.hunt_for ActionDispatch::Response do |hunt|
              hunt.fetch( AbstractController::Base ).response
            end

            hunter.hunt_for Scorpion::Rack::Env, return: request.env
          end
        end

        def assign_scorpion( scorpion )
          request.env[ENV_KEY] = scorpion
        end

        def free_scorpion
          return unless conceived_scorpion?

          scorpion.try( :destroy )
          request.env.delete ENV_KEY
        end

    end
  end
end