File: active_support/core_ext/class/inheritable_attributes.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: <Built-in Module>
  class: Class#9
inherits from
  Object ( Builtin-Module )
has properties
method: class_inheritable_reader / 1 #10
method: class_inheritable_writer / 1 #25
method: class_inheritable_array_writer / 1 #42
method: class_inheritable_hash_writer / 1 #59
method: class_inheritable_accessor / 1 #76
method: class_inheritable_array / 1 #81
method: class_inheritable_hash / 1 #86
method: inheritable_attributes #91
method: write_inheritable_attribute / 2 #95
method: write_inheritable_array / 2 #102
method: write_inheritable_hash / 2 #107
method: read_inheritable_attribute / 1 #112
method: reset_inheritable_attributes #116
constant: EMPTY_INHERITABLE_ATTRIBUTES #122
method: inherited_with_inheritable_attributes / 1 #124
alias: inherited_without_inheritable_attributes inherited #138
alias: inherited inherited_with_inheritable_attributes #139
  module: ClassInheritableAttributes#2

Class Hierarchy

Object ( Builtin-Module )
  Class    #9

Code

   1  # Retain for backward compatibility.  Methods are now included in Class.
   2  module ClassInheritableAttributes # :nodoc:
   3  end
   4 
   5  # Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
   6  # their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
   7  # to, for example, an array without those additions being shared with either their parent, siblings, or
   8  # children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
   9  class Class # :nodoc:
  10    def class_inheritable_reader(*syms)
  11      syms.each do |sym|
  12        next if sym.is_a?(Hash)
  13        class_eval <<-EOS
  14          def self.#{sym}                        # def self.before_add_for_comments
  15            read_inheritable_attribute(:#{sym})  #   read_inheritable_attribute(:before_add_for_comments)
  16          end                                    # end
  17                                                 #
  18          def #{sym}                             # def before_add_for_comments
  19            self.class.#{sym}                    #   self.class.before_add_for_comments
  20          end                                    # end
  21        EOS
  22      end
  23    end
  24 
  25    def class_inheritable_writer(*syms)
  26      options = syms.extract_options!
  27      syms.each do |sym|
  28        class_eval <<-EOS
  29          def self.#{sym}=(obj)                          # def self.color=(obj)
  30            write_inheritable_attribute(:#{sym}, obj)    #   write_inheritable_attribute(:color, obj)
  31          end                                            # end
  32                                                         #
  33          #{"                                            #
  34          def #{sym}=(obj)                               # def color=(obj)
  35            self.class.#{sym} = obj                      #   self.class.color = obj
  36          end                                            # end
  37          " unless options[:instance_writer] == false }  # # the writer above is generated unless options[:instance_writer] == false
  38        EOS
  39      end
  40    end
  41 
  42    def class_inheritable_array_writer(*syms)
  43      options = syms.extract_options!
  44      syms.each do |sym|
  45        class_eval <<-EOS
  46          def self.#{sym}=(obj)                          # def self.levels=(obj)
  47            write_inheritable_array(:#{sym}, obj)        #   write_inheritable_array(:levels, obj)
  48          end                                            # end
  49                                                         #
  50          #{"                                            #
  51          def #{sym}=(obj)                               # def levels=(obj)
  52            self.class.#{sym} = obj                      #   self.class.levels = obj
  53          end                                            # end
  54          " unless options[:instance_writer] == false }  # # the writer above is generated unless options[:instance_writer] == false
  55        EOS
  56      end
  57    end
  58 
  59    def class_inheritable_hash_writer(*syms)
  60      options = syms.extract_options!
  61      syms.each do |sym|
  62        class_eval <<-EOS
  63          def self.#{sym}=(obj)                          # def self.nicknames=(obj)
  64            write_inheritable_hash(:#{sym}, obj)         #   write_inheritable_hash(:nicknames, obj)
  65          end                                            # end
  66                                                         #
  67          #{"                                            #
  68          def #{sym}=(obj)                               # def nicknames=(obj)
  69            self.class.#{sym} = obj                      #   self.class.nicknames = obj
  70          end                                            # end
  71          " unless options[:instance_writer] == false }  # # the writer above is generated unless options[:instance_writer] == false
  72        EOS
  73      end
  74    end
  75 
  76    def class_inheritable_accessor(*syms)
  77      class_inheritable_reader(*syms)
  78      class_inheritable_writer(*syms)
  79    end
  80 
  81    def class_inheritable_array(*syms)
  82      class_inheritable_reader(*syms)
  83      class_inheritable_array_writer(*syms)
  84    end
  85 
  86    def class_inheritable_hash(*syms)
  87      class_inheritable_reader(*syms)
  88      class_inheritable_hash_writer(*syms)
  89    end
  90 
  91    def inheritable_attributes
  92      @inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
  93    end
  94 
  95    def write_inheritable_attribute(key, value)
  96      if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
  97        @inheritable_attributes = {}
  98      end
  99      inheritable_attributes[key] = value
 100    end
 101 
 102    def write_inheritable_array(key, elements)
 103      write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
 104      write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
 105    end
 106 
 107    def write_inheritable_hash(key, hash)
 108      write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
 109      write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
 110    end
 111 
 112    def read_inheritable_attribute(key)
 113      inheritable_attributes[key]
 114    end
 115 
 116    def reset_inheritable_attributes
 117      @inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
 118    end
 119 
 120    private
 121      # Prevent this constant from being created multiple times
 122      EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
 123 
 124      def inherited_with_inheritable_attributes(child)
 125        inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
 126 
 127        if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
 128          new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
 129        else
 130          new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
 131            memo.update(key => value.duplicable? ? value.dup : value)
 132          end
 133        end
 134 
 135        child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
 136      end
 137 
 138      alias inherited_without_inheritable_attributes inherited
 139      alias inherited inherited_with_inheritable_attributes
 140  end