diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb')
-rw-r--r-- | activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb index 1794afe77c..2f18666ab9 100644 --- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb @@ -10,14 +10,14 @@ class Class # :nodoc: def class_inheritable_reader(*syms) syms.each do |sym| next if sym.is_a?(Hash) - class_eval <<-EOS - def self.#{sym} # def self.before_add_for_comments - read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:before_add_for_comments) - end # end - # - def #{sym} # def before_add_for_comments - self.class.#{sym} # self.class.before_add_for_comments - end # end + class_eval(<<-EOS, __FILE__, __LINE__ + 1) + def self.#{sym} # def self.after_add + read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add) + end # end + + def #{sym} # def after_add + self.class.#{sym} # self.class.after_add + end # end EOS end end @@ -25,7 +25,7 @@ class Class # :nodoc: def class_inheritable_writer(*syms) options = syms.extract_options! syms.each do |sym| - class_eval <<-EOS + class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) # def self.color=(obj) write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj) end # end @@ -42,7 +42,7 @@ class Class # :nodoc: def class_inheritable_array_writer(*syms) options = syms.extract_options! syms.each do |sym| - class_eval <<-EOS + class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) # def self.levels=(obj) write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj) end # end @@ -59,7 +59,7 @@ class Class # :nodoc: def class_inheritable_hash_writer(*syms) options = syms.extract_options! syms.each do |sym| - class_eval <<-EOS + class_eval(<<-EOS, __FILE__, __LINE__ + 1) def self.#{sym}=(obj) # def self.nicknames=(obj) write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj) end # end @@ -138,3 +138,82 @@ class Class # :nodoc: alias inherited_without_inheritable_attributes inherited alias inherited inherited_with_inheritable_attributes end + +class Class + # Defines class-level inheritable attribute reader. Attributes are available to subclasses, + # each subclass has a copy of parent's attribute. + # + # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for. + # @return <Array[#to_s]> Array of attributes converted into inheritable_readers. + # + # @api public + # + # @todo Do we want to block instance_reader via :instance_reader => false + # @todo It would be preferable that we do something with a Hash passed in + # (error out or do the same as other methods above) instead of silently + # moving on). In particular, this makes the return value of this function + # less useful. + def extlib_inheritable_reader(*ivars) + instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash) + + ivars.each do |ivar| + self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def self.#{ivar} + return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar}) + ivar = superclass.#{ivar} + return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}") + @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar + end + RUBY + unless instance_reader == false + self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{ivar} + self.class.#{ivar} + end + RUBY + end + end + end + + # Defines class-level inheritable attribute writer. Attributes are available to subclasses, + # each subclass has a copy of parent's attribute. + # + # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to + # define inheritable writer for. + # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined. + # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers. + # + # @api public + # + # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it + # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere. + def extlib_inheritable_writer(*ivars) + instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash) + ivars.each do |ivar| + self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def self.#{ivar}=(obj) + @#{ivar} = obj + end + RUBY + unless instance_writer == false + self.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{ivar}=(obj) self.class.#{ivar} = obj end + RUBY + end + end + end + + # Defines class-level inheritable attribute accessor. Attributes are available to subclasses, + # each subclass has a copy of parent's attribute. + # + # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to + # define inheritable accessor for. + # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined. + # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors. + # + # @api public + def extlib_inheritable_accessor(*syms) + extlib_inheritable_reader(*syms) + extlib_inheritable_writer(*syms) + end +end
\ No newline at end of file |