Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/tags/rel_1-2-3/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb

Revision 6116, 4.1 kB (checked in by rick, 3 years ago)

fix problem with EMPTY_INHERITABLE_ATTRIBUTES being redefined

Line 
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}
15           read_inheritable_attribute(:#{sym})
16         end
17
18         def #{sym}
19           self.class.#{sym}
20         end
21       EOS
22     end
23   end
24
25   def class_inheritable_writer(*syms)
26     options = syms.last.is_a?(Hash) ? syms.pop : {}
27     syms.each do |sym|
28       class_eval <<-EOS
29         def self.#{sym}=(obj)
30           write_inheritable_attribute(:#{sym}, obj)
31         end
32
33         #{"
34         def #{sym}=(obj)
35           self.class.#{sym} = obj
36         end
37         " unless options[:instance_writer] == false }
38       EOS
39     end
40   end
41
42   def class_inheritable_array_writer(*syms)
43     options = syms.last.is_a?(Hash) ? syms.pop : {}
44     syms.each do |sym|
45       class_eval <<-EOS
46         def self.#{sym}=(obj)
47           write_inheritable_array(:#{sym}, obj)
48         end
49
50         #{"
51         def #{sym}=(obj)
52           self.class.#{sym} = obj
53         end
54         " unless options[:instance_writer] == false }
55       EOS
56     end
57   end
58
59   def class_inheritable_hash_writer(*syms)
60     options = syms.last.is_a?(Hash) ? syms.pop : {}
61     syms.each do |sym|
62       class_eval <<-EOS
63         def self.#{sym}=(obj)
64           write_inheritable_hash(:#{sym}, obj)
65         end
66
67         #{"
68         def #{sym}=(obj)
69           self.class.#{sym} = obj
70         end
71         " 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.dup rescue 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
Note: See TracBrowser for help on using the browser.