Skip to content
This repository
tag: v3.2.3
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 148 lines (129 sloc) 4.257 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
require 'set'

module ActiveModel
  # Stores the enabled/disabled state of individual observers for
  # a particular model class.
  class ObserverArray < Array
    attr_reader :model_class
    def initialize(model_class, *args)
      @model_class = model_class
      super(*args)
    end

    # Returns true if the given observer is disabled for the model class.
    def disabled_for?(observer)
      disabled_observers.include?(observer.class)
    end

    # Disables one or more observers. This supports multiple forms:
    #
    # ORM.observers.disable :user_observer
    # # => disables the UserObserver
    #
    # User.observers.disable AuditTrail
    # # => disables the AuditTrail observer for User notifications.
    # # Other models will still notify the AuditTrail observer.
    #
    # ORM.observers.disable :observer_1, :observer_2
    # # => disables Observer1 and Observer2 for all models.
    #
    # ORM.observers.disable :all
    # # => disables all observers for all models.
    #
    # User.observers.disable :all do
    # # all user observers are disabled for
    # # just the duration of the block
    # end
    def disable(*observers, &block)
      set_enablement(false, observers, &block)
    end

    # Enables one or more observers. This supports multiple forms:
    #
    # ORM.observers.enable :user_observer
    # # => enables the UserObserver
    #
    # User.observers.enable AuditTrail
    # # => enables the AuditTrail observer for User notifications.
    # # Other models will not be affected (i.e. they will not
    # # trigger notifications to AuditTrail if previously disabled)
    #
    # ORM.observers.enable :observer_1, :observer_2
    # # => enables Observer1 and Observer2 for all models.
    #
    # ORM.observers.enable :all
    # # => enables all observers for all models.
    #
    # User.observers.enable :all do
    # # all user observers are enabled for
    # # just the duration of the block
    # end
    #
    # Note: all observers are enabled by default. This method is only
    # useful when you have previously disabled one or more observers.
    def enable(*observers, &block)
      set_enablement(true, observers, &block)
    end

    protected

      def disabled_observers
        @disabled_observers ||= Set.new
      end

      def observer_class_for(observer)
        return observer if observer.is_a?(Class)

        if observer.respond_to?(:to_sym) # string/symbol
          observer.to_s.camelize.constantize
        else
          raise ArgumentError, "#{observer} was not a class or a " +
            "lowercase, underscored class name as expected."
        end
      end

      def start_transaction
        disabled_observer_stack.push(disabled_observers.dup)
        each_subclass_array do |array|
          array.start_transaction
        end
      end

      def disabled_observer_stack
        @disabled_observer_stack ||= []
      end

      def end_transaction
        @disabled_observers = disabled_observer_stack.pop
        each_subclass_array do |array|
          array.end_transaction
        end
      end

      def transaction
        start_transaction

        begin
          yield
        ensure
          end_transaction
        end
      end

      def each_subclass_array
        model_class.descendants.each do |subclass|
          yield subclass.observers
        end
      end

      def set_enablement(enabled, observers)
        if block_given?
          transaction do
            set_enablement(enabled, observers)
            yield
          end
        else
          observers = ActiveModel::Observer.descendants if observers == [:all]
          observers.each do |obs|
            klass = observer_class_for(obs)

            unless klass < ActiveModel::Observer
              raise ArgumentError.new("#{obs} does not refer to a valid observer")
            end

            if enabled
              disabled_observers.delete(klass)
            else
              disabled_observers << klass
            end
          end

          each_subclass_array do |array|
            array.set_enablement(enabled, observers)
          end
        end
      end
  end
end
Something went wrong with that request. Please try again.