2016-12-25 73 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
相关问题