2014-09-30 24 views
0

我在Designer類兩種方法(在我的Rails應用程序):爲什麼我的define_method不起作用?

def add_specialty(specialty) 
    specialty_list.add(specialty) 
    save 
    end 

    def add_qualification(qualification) 
    qualification_list.add(qualification) 
    save 
    end 

下面是規範我對他們所傳遞:

context 'adding specialties' do 
    it "can add a new specialty" do 
     expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1) 
     expect(designer.specialty_list).to include("interior design") 
    end 
    end 

    context 'adding qualifications' do 
    it "can add a new qualification" do 
     expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1) 
     expect(designer.qualification_list).to include("architect") 
    end 
    end 

現在我想重構這個實施:

["specialty", "qualification"].each do |attr| 
    define_method("add_#{attr}") do |arg| 
     "#{attr}_list".add(arg) 
     save 
    end 
    end 

失敗。我得到失敗:

1) Designer adding qualifications can add a new qualification 
    Failure/Error: expect { designer.add_qualification("architect") }.to change {designer.qualification_list.count}.by(1) 
    NoMethodError: 
     undefined method `add' for "qualification_list":String 
    # ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>' 
    # ./spec/models/designer_spec.rb:79:in `block (4 levels) in <top (required)>' 
    # ./spec/models/designer_spec.rb:79:in `block (3 levels) in <top (required)>' 
    # -e:1:in `<main>' 

    2) Designer adding specialties can add a new specialty 
    Failure/Error: expect { designer.add_specialty("interior design") }.to change {designer.specialty_list.count}.by(1) 
    NoMethodError: 
     undefined method `add' for "specialty_list":String 
    # ./app/models/designer.rb:93:in `block (2 levels) in <class:Designer>' 
    # ./spec/models/designer_spec.rb:72:in `block (4 levels) in <top (required)>' 
    # ./spec/models/designer_spec.rb:72:in `block (3 levels) in <top (required)>' 
    # -e:1:in `<main>' 

我在做define_method實施時做錯了什麼?

回答

1

"#{attr}_list"本身就是字符串"specialty_list""qualification_list",並且字符串沒有添加方法。我想你想要send的方法,例如

%w{ specialty qualification }.each do |attr| 
    define_method("add_#{attr}") do |arg| 
    send("#{attr}_list").add(arg) 
    save 
    end 
end 
+0

噢!這樣好多了。我們發送的「自我」是類的實例 - 對嗎?使用'instance_eval'也危險嗎? – 2014-09-30 05:24:26

+1

是的,確切地說,隱含的「自我」接收者是這個類的實例。我不認爲'instance_eval'是危險的,可能更適合不同的用例(需要強制值'self')。 [一些額外的信息](http://stackoverflow.com/questions/3071532/how-does-instance-eval-work-and-why-does-dhh-hate-it/3071983#3071983)。 – Ben 2014-09-30 05:29:08

0

好:我得到它的工作是這樣的:

["specialty", "qualification"].each do |attr| 
    define_method("add_#{attr}") do |arg| 
     instance_eval("#{attr}_list").send(:add, arg) 
     save 
    end 
    end 

不知道爲什麼,這個工作雖然還是如果以正確的方式來做到這一點。任何人都會關心爲更好的理解做出貢獻嗎?

+0

@Ben,我試着用'send',但還是抱怨。我認爲我需要'instance_eval'來調用底層方法 - 不確定 – 2014-09-30 05:22:34