2010-08-14 23 views
0

我想給我的車型之一的屬性訪問器默認的八個零的數組。這是第一個語法我想:如何使attr_accessor_with_default與集合一起工作?

attr_accessor_with_default:weekly_magnitude_list, [0,0,0,0,0,0,0,0] 

上面並沒有做什麼,我預料的,因爲該模型的所有實例結束共享相同的Array對象。該避讓我到了博客(http://barelyenough.org/blog/2007/09/things-to-be-suspicious-of-attr_accessor_with_default-with-a-collection/)提出了不同的語法,基本上包裹在一個塊中的默認值。

attr_accessor_with_default(:weekly_magnitude_list) {[0,0,0,0,0,0,0,0]} 

這不起作用(對我來說,在Rails 3中)。任何時候我調用訪問器,我似乎都會得到一個全新的Array對象。這實際上意味着我無法寫信給它。

有誰知道正確的方式做到這一點?

爲了您的快樂,我已經包含了簡單的測試,證明了該輸出:

class Container 
    attr_accessor_with_default :naive_collection, [0,0] 
    attr_accessor_with_default(:block_collection) {[0,0]} 
end 
> c = Container.new 
=> #<Container:0x7f3610f717a8> 
> c.naive_collection[0] = "foo" 
=> "foo" 
> Container.new.naive_collection 
=> ["foo", 0] 
# expected [0,0] 

> c.block_collection[0] = "foo" 
=> "foo" 
> c.block_collection 
=> [0, 0] 
# expected ["foo", 0] 

回答

1

我只是偶然在這個問題上運行同樣的問題一段時間。

作爲參考,docs指定塊的形式實例中的動態範圍評價。要繼續的例子,它的用處實在是相當有限的,但至少工作你所期望的方式:

class Container 
    attr_accessor_with_default(:block_collection) { name.underscore } 
end 

> c = Container.new(:name => "TestName") 
> c.block_collection # => "test_name" 
> c.block_collection = "something else" # => "something else" 
> c.name => "TestName" 

這裏是真正古怪的一部分,儘管...

class Container 
    attr_accessor_with_default :naive_collection, [0, 0] 
end 

# This works as expected 
> c = Container.new 
> c.naive_collection = ["foo", "bar"] # => ["foo", "bar"] 
> Container.new.naive_collection # => [0, 0] 
> c.naive_collection[0] = 0 # => [0, "bar"] 
> Container.new.naive_collection # => [0, 0] 

# But this doesn't 
> c2 = Container.new 
> c2.naive_collection # => [0, 0] 
> c2.naive_collection[0] = "problem!" # => ["problem!", 0] 
> Container.new.naive_collection # => ["problem!", 0] 

挖掘到的源我看到attr_accessor_with_default定義了一個返回默認值或執行塊的實例方法。這很好。

然後它前進到module_eval中執行此:

def #{sym}=(value) 
    class << self; 
    attr_reader :#{sym} 
    end 

    @#{sym} = value 
end 

這僅僅是可笑的令人費解。如果我無法弄清楚這種行爲的動機,我最終可能會將此作爲一個錯誤發售。

更新:

我設法弄清楚發生了什麼事情錯在這裏。

def attr_accessor_with_default(sym, default = Proc.new) 
    define_method(sym, block_given? ? default : Proc.new { default }) 
    module_eval(<<-EVAL, __FILE__, __LINE__ + 1) 
    def #{sym}=(value) 
     class << self; attr_accessor :#{sym} end 
     @#{sym} = value 
    end 
    EVAL 
end 

最初,缺省值作爲proc存在。 一旦你調用設置,getter和setter方法由attr_accessor方法覆蓋,實例變量初始化。 的問題是,在吸氣的默認PROC返回類級別的默認值。所以,當你做這樣的事情:

> c2.naive_collection[0] = "problem!" # => ["problem!", 0] 

你實際上改變了類的默認值。

我覺得這個方法可能應爲實施:

class Module 
    def attr_accessor_with_default(sym, default = Proc.new) 
    module_eval(<<-EVAL, __FILE__, __LINE__ + 1) 
     def #{sym} 
     class << self; attr_reader :#{sym} end 
     @#{sym} = #{ default.dup } 
     end 

     def #{sym}=(value) 
     class << self; attr_accessor :#{sym} end 
     @#{sym} = value 
     end 
    EVAL 
    end 
end 

我會門票,並提供了一個補丁。再次

更新: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/6496

相關問題