提交 3529e58e 编写于 作者: W willnet

Fix `thread_mattr_accessor` share variable superclass with subclass

The current implementation of `thread_mattr_accessor` set variable
sharing superclass with subclass. So the method doesn't work as documented.

Precondition

    class Account
      thread_mattr_accessor :user
    end

    class Customer < Account
    end

    Account.user = "DHH"
    Account.user  #=> "DHH"
    Customer.user = "Rafael"
    Customer.user # => "Rafael"

Documented behavior

    Account.user  # => "DHH"

Actual behavior

    Account.user  # => "Rafael"

Current implementation set variable statically likes `Thread[:attr_Account_user]`,
and customer also use it.

Make variable name dynamic to use own thread-local variable.
上级 5b469da6
* Fix `thread_mattr_accessor` share variable superclass with subclass
The current implementation of `thread_mattr_accessor` set variable
sharing superclass with subclass. So the method doesn't work as documented.
*Shinichi Maeshima*
* Since weeks are no longer converted to days, add `:weeks` to the list of
parts that `ActiveSupport::TimeWithZone` will recognize as possibly being
of variable duration to take account of DST transitions.
......
......@@ -41,14 +41,14 @@ def thread_mattr_reader(*syms)
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}
Thread.current[:"attr_#{name}_#{sym}"]
Thread.current["attr_"+ name + "_#{sym}"]
end
EOS
unless options[:instance_reader] == false || options[:instance_accessor] == false
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}
Thread.current[:"attr_#{name}_#{sym}"]
Thread.current["attr_"+ self.class.name + "_#{sym}"]
end
EOS
end
......@@ -80,14 +80,14 @@ def thread_mattr_writer(*syms)
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj)
Thread.current[:"attr_#{name}_#{sym}"] = obj
Thread.current["attr_"+ name + "_#{sym}"] = obj
end
EOS
unless options[:instance_writer] == false || options[:instance_accessor] == false
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{sym}=(obj)
Thread.current[:"attr_#{name}_#{sym}"] = obj
Thread.current["attr_"+ self.class.name + "_#{sym}"] = obj
end
EOS
end
......
......@@ -8,6 +8,16 @@ def setup
thread_mattr_accessor :bar, instance_writer: false
thread_mattr_reader :shaq, instance_reader: false
thread_mattr_accessor :camp, instance_accessor: false
def self.name
'MyClass'
end
end
@subclass = Class.new(@class) do
def self.name
'SubMyClass'
end
end
@object = @class.new
......@@ -65,15 +75,15 @@ def test_values_should_not_bleed_between_threads
threads << Thread.new do
@class.foo = 'other things'
sleep 1
assert_equal 'other things', @class.foo
assert_equal 'other things', @class.foo
end
threads << Thread.new do
@class.foo = 'really other things'
sleep 1
assert_equal 'really other things', @class.foo
assert_equal 'really other things', @class.foo
end
threads.each { |t| t.join }
end
......@@ -112,4 +122,14 @@ def test_should_return_same_value_by_class_or_instance_accessor
assert_equal @class.foo, @object.foo
end
def test_should_not_affect_superclass_if_subclass_set_value
@class.foo = 'super'
assert_equal @class.foo, 'super'
assert_nil @subclass.foo
@subclass.foo = 'sub'
assert_equal @class.foo, 'super'
assert_equal @subclass.foo, 'sub'
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册