1 require 'active_support/core_ext/kernel/singleton_class'
2 require 'active_support/core_ext/module/remove_method'
3
4 class Class
5 # Declare a class-level attribute whose value is inheritable and
6 # overwritable by subclasses:
7 #
8 # class Base
9 # class_attribute :setting
10 # end
11 #
12 # class Subclass < Base
13 # end
14 #
15 # Base.setting = true
16 # Subclass.setting # => true
17 # Subclass.setting = false
18 # Subclass.setting # => false
19 # Base.setting # => true
20 #
21 # This matches normal Ruby method inheritance: think of writing an attribute
22 # on a subclass as overriding the reader method.
23 #
24 # For convenience, a query method is defined as well:
25 #
26 # Subclass.setting? # => false
27 #
28 # Instances may overwrite the class value in the same way:
29 #
30 # Base.setting = true
31 # object = Base.new
32 # object.setting # => true
33 # object.setting = false
34 # object.setting # => false
35 # Base.setting # => true
36 #
37 # To opt out of the instance writer method, pass :instance_writer => false.
38 #
39 # object.setting = false # => NoMethodError
40 def class_attribute(*attrs)
41 instance_writer = !attrs.last.is_a?(Hash) || attrs.pop[:instance_writer]
42
43 attrs.each do |name|
44 class_eval <<-RUBY, __FILE__, __LINE__ + 1
45 def self.#{name}() nil end
46 def self.#{name}?() !!#{name} end
47
48 def self.#{name}=(val)
49 singleton_class.class_eval do
50 remove_possible_method(:#{name})
51 define_method(:#{name}) { val }
52 end
53 end
54
55 def #{name}
56 defined?(@#{name}) ? @#{name} : singleton_class.#{name}
57 end
58
59 def #{name}?
60 !!#{name}
61 end
62 RUBY
63
64 attr_writer name if instance_writer
65 end
66 end
67 end