mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
class_attribute gets instance methods which delegate to but may override their class values as you'd expect. Disable instance writer methods with :instance_writer => false.
This commit is contained in:
parent
47d252f992
commit
60bbf16bfd
2 changed files with 48 additions and 12 deletions
|
@ -24,14 +24,35 @@ class Class
|
||||||
# For convenience, a query method is defined as well:
|
# For convenience, a query method is defined as well:
|
||||||
#
|
#
|
||||||
# Subclass.setting? # => false
|
# 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)
|
def class_attribute(*attrs)
|
||||||
|
instance_writer = !attrs.last.is_a?(Hash) || attrs.pop[:instance_writer]
|
||||||
|
|
||||||
s = singleton_class
|
s = singleton_class
|
||||||
attrs.each do |attr|
|
attrs.each do |attr|
|
||||||
s.send(:define_method, attr) { }
|
s.send(:define_method, attr) { }
|
||||||
s.send(:define_method, "#{attr}?") { !!send(attr) }
|
s.send(:define_method, :"#{attr}?") { !!send(attr) }
|
||||||
s.send(:define_method, "#{attr}=") do |value|
|
s.send(:define_method, :"#{attr}=") do |value|
|
||||||
singleton_class.send(:define_method, attr) { value }
|
singleton_class.send(:define_method, attr) { value }
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,13 +2,6 @@ require 'abstract_unit'
|
||||||
require 'active_support/core_ext/class/attribute'
|
require 'active_support/core_ext/class/attribute'
|
||||||
|
|
||||||
class ClassAttributeTest < ActiveSupport::TestCase
|
class ClassAttributeTest < ActiveSupport::TestCase
|
||||||
class Base
|
|
||||||
class_attribute :setting
|
|
||||||
end
|
|
||||||
|
|
||||||
class Subclass < Base
|
|
||||||
end
|
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@klass = Class.new { class_attribute :setting }
|
@klass = Class.new { class_attribute :setting }
|
||||||
@sub = Class.new(@klass)
|
@sub = Class.new(@klass)
|
||||||
|
@ -40,8 +33,30 @@ class ClassAttributeTest < ActiveSupport::TestCase
|
||||||
assert_equal true, @klass.setting?
|
assert_equal true, @klass.setting?
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'no instance delegates' do
|
test 'instance reader delegates to class' do
|
||||||
assert_raise(NoMethodError) { @klass.new.setting }
|
assert_nil @klass.new.setting
|
||||||
assert_raise(NoMethodError) { @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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue