2016-12-25 75 views
0

代碼:爲什麼這個屬性編寫器不被調用?

class Weird 
    DEFAULT_FOO = 'fo0' 

    attr_accessor :foo 

    def initialize(val) 
    @foo = val 
    end 

    def run 
    unless foo 
     foo = DEFAULT_FOO   # Fails 
     # @foo = DEFAULT_FOO  # Works 
    end 

    bar(foo) 
    end 

    def bar(f) 
    puts "The foo is '#{f}'" 
    end 
end 

RSpec.describe Weird do 
    subject(:weird) do 
    described_class.new(foo_val) 
    end 
    let(:foo_val) { nil } 

    describe '#run' do 
    context 'without foo' do 
     it 'bars the foo' do 
     expect(subject).to receive(:bar).with(described_class::DEFAULT_FOO) 
     subject.run 
     end 
    end 

    context 'with foo' do 
     let(:foo_val) { 'quux' } 

     it 'bars the foo' do 
     expect(subject).to receive(:bar).with(foo_val) 
     subject.run 
     end 
    end 
    end 
end 

使用RSpec(rspec weird.rb)運行此和第二測試失敗:

1) Weird#run with foo bars the foo 
    Failure/Error: bar(foo) 

     #<Weird:0x007fc1948727f8 @foo="quux"> received :bar with unexpected arguments 
     expected: ("quux") 
       got: (nil) 
     Diff: 
     @@ -1,2 +1,2 @@ 
     -["quux"] 
     +[nil] 

    # ./test_case_2.rb:21:in `run' 
    # ./test_case_2.rb:48:in `block (4 levels) in <top (required)>' 

的隱式定義的foo=()屬性寫入器方法不被調用;明確定義一個也不起作用。相反,它似乎是一個方法 - 局部變量foo正在創建(並設置)它不應該。這是爲什麼發生?

紅寶石版本是ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin15]

+0

怎麼樣'富|| = DEFAULT_FOO'? –

+1

這不會出於完全相同的原因。 –

回答

1

foo = DEFAULT_FOO失敗,因爲這是創建一個局部變量foo並將其分配值DEFAULT_FOO。但是當你打電話給bar(foo)時,它會首先查找@值,在這種情況下,它仍然是零。

分配實例變量時,您必須使用self.foo =@foo =

+0

考慮將'attr_accessor'設置爲private,除非您打算將它暴露給外部類。如果您需要以只讀方式公開它,請使用'attr_reader'作爲公共方法,'attr_writer'作爲私有方法。 – moveson

+0

@moveson。私人'attr_writer',爲什麼?只需使用'@ foo =「bar」' –

+3

@EricDuminil:方法可以被覆蓋,重構,掛鉤,別名。 Ivars不能。 –

0

2種方式來解決

  1. 使用self.foo = DEFAULT_FOO
  2. 使用@foo = DEFAULT_FOO
相關問題