Permalink
Browse files

class_attribute gets instance methods which delegate to but may overr…

…ide their class values as you'd expect. Disable instance writer methods with :instance_writer => false.
  • Loading branch information...
1 parent 47d252f commit 60bbf16bfd60493c05bf9c9c70ec962a0c482155 @jeremy jeremy committed Mar 9, 2010
@@ -24,14 +24,35 @@ class Class
# For convenience, a query method is defined as well:
#
# Subclass.setting? # => false
+ #
+ # Instances may overwrite the class value in the same way:
+ #
+ # Base.setting = true
+ # object = Base.new
+ # object.setting # => true
+ # object.setting = false
+ # object.setting # => false
+ # Base.setting # => true
+ #
+ # To opt out of the instance writer method, pass :instance_writer => false.
+ #
+ # object.setting = false # => NoMethodError
def class_attribute(*attrs)
+ instance_writer = !attrs.last.is_a?(Hash) || attrs.pop[:instance_writer]
+
s = singleton_class
attrs.each do |attr|
s.send(:define_method, attr) { }
- s.send(:define_method, "#{attr}?") { !!send(attr) }
- s.send(:define_method, "#{attr}=") do |value|
+ s.send(:define_method, :"#{attr}?") { !!send(attr) }
+ s.send(:define_method, :"#{attr}=") do |value|
singleton_class.send(:define_method, attr) { value }
end
+
+ define_method(attr) { self.class.send(attr) }
+ define_method(:"#{attr}?") { !!send(attr) }
+ define_method(:"#{attr}=") do |value|
+ singleton_class.send(:define_method, attr) { value }
+ end if instance_writer
end
end
end
@@ -2,13 +2,6 @@
require 'active_support/core_ext/class/attribute'
class ClassAttributeTest < ActiveSupport::TestCase
- class Base
- class_attribute :setting
- end
-
- class Subclass < Base
- end
-
def setup
@klass = Class.new { class_attribute :setting }
@sub = Class.new(@klass)
@@ -40,8 +33,30 @@ def setup
assert_equal true, @klass.setting?
end
- test 'no instance delegates' do
- assert_raise(NoMethodError) { @klass.new.setting }
- assert_raise(NoMethodError) { @klass.new.setting? }
+ test 'instance reader delegates to class' do
+ assert_nil @klass.new.setting
+
+ @klass.setting = 1
+ assert_equal 1, @klass.new.setting
+ end
+
+ test 'instance override' do
+ object = @klass.new
+ object.setting = 1
+ assert_nil @klass.setting
+ @klass.setting = 2
+ assert_equal 1, object.setting
+ end
+
+ test 'instance query' do
+ object = @klass.new
+ assert_equal false, object.setting?
+ object.setting = 1
+ assert_equal true, object.setting?
+ end
+
+ test 'disabling instance writer' do
+ object = Class.new { class_attribute :setting, :instance_writer => false }.new
+ assert_raise(NoMethodError) { object.setting = 'boom' }
end
end

1 comment on commit 60bbf16

@simonjefford
Contributor

This commit triggers a whole load of deprecation warnings from the actionpack unit tests at http://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/url_for.rb#L155

Please sign in to comment.