2007-01-22 14:43:50 +01:00
|
|
|
# Retain for backward compatibility. Methods are now included in Class.
|
|
|
|
module ClassInheritableAttributes # :nodoc:
|
|
|
|
end
|
|
|
|
|
|
|
|
# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
|
|
|
|
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
|
|
|
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
|
|
|
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
|
|
|
class Class # :nodoc:
|
|
|
|
def class_inheritable_reader(*syms)
|
|
|
|
syms.each do |sym|
|
2007-02-09 09:04:31 +01:00
|
|
|
next if sym.is_a?(Hash)
|
2007-01-22 14:43:50 +01:00
|
|
|
class_eval <<-EOS
|
|
|
|
def self.#{sym}
|
|
|
|
read_inheritable_attribute(:#{sym})
|
|
|
|
end
|
|
|
|
|
|
|
|
def #{sym}
|
|
|
|
self.class.#{sym}
|
|
|
|
end
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_writer(*syms)
|
2007-12-21 08:48:59 +01:00
|
|
|
options = syms.extract_options!
|
2007-01-22 14:43:50 +01:00
|
|
|
syms.each do |sym|
|
|
|
|
class_eval <<-EOS
|
|
|
|
def self.#{sym}=(obj)
|
|
|
|
write_inheritable_attribute(:#{sym}, obj)
|
|
|
|
end
|
|
|
|
|
2007-02-09 09:04:31 +01:00
|
|
|
#{"
|
2007-01-22 14:43:50 +01:00
|
|
|
def #{sym}=(obj)
|
|
|
|
self.class.#{sym} = obj
|
|
|
|
end
|
2007-02-09 09:04:31 +01:00
|
|
|
" unless options[:instance_writer] == false }
|
2007-01-22 14:43:50 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_array_writer(*syms)
|
2007-12-21 08:48:59 +01:00
|
|
|
options = syms.extract_options!
|
2007-01-22 14:43:50 +01:00
|
|
|
syms.each do |sym|
|
|
|
|
class_eval <<-EOS
|
|
|
|
def self.#{sym}=(obj)
|
|
|
|
write_inheritable_array(:#{sym}, obj)
|
|
|
|
end
|
|
|
|
|
2007-02-09 09:04:31 +01:00
|
|
|
#{"
|
2007-01-22 14:43:50 +01:00
|
|
|
def #{sym}=(obj)
|
|
|
|
self.class.#{sym} = obj
|
|
|
|
end
|
2007-02-09 09:04:31 +01:00
|
|
|
" unless options[:instance_writer] == false }
|
2007-01-22 14:43:50 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_hash_writer(*syms)
|
2007-12-21 08:48:59 +01:00
|
|
|
options = syms.extract_options!
|
2007-01-22 14:43:50 +01:00
|
|
|
syms.each do |sym|
|
|
|
|
class_eval <<-EOS
|
|
|
|
def self.#{sym}=(obj)
|
|
|
|
write_inheritable_hash(:#{sym}, obj)
|
|
|
|
end
|
|
|
|
|
2007-02-09 09:04:31 +01:00
|
|
|
#{"
|
2007-01-22 14:43:50 +01:00
|
|
|
def #{sym}=(obj)
|
|
|
|
self.class.#{sym} = obj
|
|
|
|
end
|
2007-02-09 09:04:31 +01:00
|
|
|
" unless options[:instance_writer] == false }
|
2007-01-22 14:43:50 +01:00
|
|
|
EOS
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_accessor(*syms)
|
|
|
|
class_inheritable_reader(*syms)
|
|
|
|
class_inheritable_writer(*syms)
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_array(*syms)
|
|
|
|
class_inheritable_reader(*syms)
|
|
|
|
class_inheritable_array_writer(*syms)
|
|
|
|
end
|
|
|
|
|
|
|
|
def class_inheritable_hash(*syms)
|
|
|
|
class_inheritable_reader(*syms)
|
|
|
|
class_inheritable_hash_writer(*syms)
|
|
|
|
end
|
|
|
|
|
|
|
|
def inheritable_attributes
|
2007-02-09 09:04:31 +01:00
|
|
|
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def write_inheritable_attribute(key, value)
|
2007-02-09 09:04:31 +01:00
|
|
|
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
|
|
|
@inheritable_attributes = {}
|
|
|
|
end
|
2007-01-22 14:43:50 +01:00
|
|
|
inheritable_attributes[key] = value
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_inheritable_array(key, elements)
|
|
|
|
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
|
|
|
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
|
|
|
end
|
|
|
|
|
|
|
|
def write_inheritable_hash(key, hash)
|
|
|
|
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
|
|
|
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
|
|
|
end
|
|
|
|
|
|
|
|
def read_inheritable_attribute(key)
|
|
|
|
inheritable_attributes[key]
|
|
|
|
end
|
|
|
|
|
|
|
|
def reset_inheritable_attributes
|
2007-02-09 09:04:31 +01:00
|
|
|
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
2007-02-09 09:04:31 +01:00
|
|
|
private
|
|
|
|
# Prevent this constant from being created multiple times
|
|
|
|
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
|
|
|
|
|
2007-01-22 14:43:50 +01:00
|
|
|
def inherited_with_inheritable_attributes(child)
|
|
|
|
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
2007-02-09 09:04:31 +01:00
|
|
|
|
|
|
|
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
|
|
|
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
|
|
|
else
|
|
|
|
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
|
2008-06-02 08:35:38 +02:00
|
|
|
memo.update(key => value.duplicable? ? value.dup : value)
|
2007-02-09 09:04:31 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
2007-01-22 14:43:50 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
alias inherited_without_inheritable_attributes inherited
|
|
|
|
alias inherited inherited_with_inheritable_attributes
|
|
|
|
end
|