Skip to content
This repository
tag: v2.3.2
Fetching contributors…

Cannot retrieve contributors at this time

file 98 lines (84 sloc) 2.839 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
require 'observer'
require 'singleton'
require 'active_model/core'

module ActiveModel
  module Observing
    module ClassMethods
      def observers
        @observers ||= []
      end
      
      def observers=(*values)
        @observers = values.flatten
      end
      
      def instantiate_observers
        observers.each { |o| instantiate_observer(o) }
      end
    
    protected
      def instantiate_observer(observer)
        # string/symbol
        if observer.respond_to?(:to_sym)
          observer = observer.to_s.camelize.constantize.instance
        elsif observer.respond_to?(:instance)
          observer.instance
        else
          raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
        end
      end
      
      # Notify observers when the observed class is subclassed.
      def inherited(subclass)
        super
        changed
        notify_observers :observed_class_inherited, subclass
      end
    end
    
    def self.included(receiver)
      receiver.extend Observable, ClassMethods
    end
  end

  class Observer
    include Singleton
    attr_writer :observed_classes

    class << self
      attr_accessor :models
      # Attaches the observer to the supplied model classes.
      def observe(*models)
        @models = models.flatten
        @models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
      end

      def observed_class_name
        @observed_class_name ||=
          if guessed_name = name.scan(/(.*)Observer/)[0]
            @observed_class_name = guessed_name[0]
          end
      end

      # The class observed by default is inferred from the observer's class name:
      # assert_equal [Person], PersonObserver.observed_class
      def observed_class
        if observed_class_name
          observed_class_name.constantize
        else
          nil
        end
      end
    end

    # Start observing the declared classes and their subclasses.
    def initialize
      self.observed_classes = self.class.models if self.class.models
      observed_classes.each { |klass| klass.add_observer(self) }
    end

    # Send observed_method(object) if the method exists.
    def update(observed_method, object) #:nodoc:
      send(observed_method, object) if respond_to?(observed_method)
    end

    # Special method sent by the observed class when it is inherited.
    # Passes the new subclass.
    def observed_class_inherited(subclass) #:nodoc:
      self.class.observe(observed_classes + [subclass])
      subclass.add_observer(self)
    end

  protected
    def observed_classes
      @observed_classes ||= [self.class.observed_class]
    end
  end
end
Something went wrong with that request. Please try again.