2014-09-30 27 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